diff --git a/carousel-slider/README.md b/carousel-slider/README.md new file mode 100644 index 0000000..67466f4 --- /dev/null +++ b/carousel-slider/README.md @@ -0,0 +1,178 @@ +# CarouselSlider + +An advanced carousel component that displays one slide at a time with smooth transitions between slides. + +## Getting Started + +Install dependencies: +```bash +npm install +``` + +Share the component to your Webflow workspace: +```bash +npx webflow library share +``` + +For local development: +```bash +npm run dev +``` + +## Designer Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| ID | Id | — | HTML ID attribute for targeting and accessibility | +| Transition Effect | Variant | slide | Animation style for slide transitions (slide or fade) | +| Aspect Ratio | Variant | 16:9 | Slide container aspect ratio (16:9, 4:3, 21:9, 1:1, or 3:2) | +| Show Peek | Boolean | false | Show peek of adjacent slides on desktop | +| Auto Play | Boolean | true | Enable automatic slide progression | +| Auto Play Interval | Number | 5000 | Milliseconds between auto-play transitions | +| Pause On Hover | Boolean | true | Pause auto-play when hovering over carousel | +| Enable Loop | Boolean | true | Loop from last slide back to first | +| Show Arrows | Boolean | true | Display previous/next navigation arrows | +| Show Dots | Boolean | true | Display dot indicators below slides | +| Slide 1 Visible | Visibility | — | Show or hide slide 1 | +| Slide 1 Image | Image | — | Slide 1 background or featured image | +| Slide 1 Title | Text | Discover Amazing Features | Slide 1 main heading text | +| Slide 1 Description | Text | Experience the next generation... | Slide 1 descriptive text content | +| Slide 1 CTA Text | Text | Learn More | Slide 1 call-to-action button text | +| Slide 1 CTA Link | Link | — | Slide 1 call-to-action button link | +| Slide 1 Show CTA | Boolean | true | Display the CTA button on slide 1 | +| Slide 2 Visible | Visibility | — | Show or hide slide 2 | +| Slide 2 Image | Image | — | Slide 2 background or featured image | +| Slide 2 Title | Text | Built for Performance | Slide 2 main heading text | +| Slide 2 Description | Text | Lightning-fast performance... | Slide 2 descriptive text content | +| Slide 2 CTA Text | Text | Get Started | Slide 2 call-to-action button text | +| Slide 2 CTA Link | Link | — | Slide 2 call-to-action button link | +| Slide 2 Show CTA | Boolean | true | Display the CTA button on slide 2 | +| Slide 3 Visible | Visibility | — | Show or hide slide 3 | +| Slide 3 Image | Image | — | Slide 3 background or featured image | +| Slide 3 Title | Text | Trusted by Thousands | Slide 3 main heading text | +| Slide 3 Description | Text | Join thousands of satisfied... | Slide 3 descriptive text content | +| Slide 3 CTA Text | Text | View Testimonials | Slide 3 call-to-action button text | +| Slide 3 CTA Link | Link | — | Slide 3 call-to-action button link | +| Slide 3 Show CTA | Boolean | true | Display the CTA button on slide 3 | +| Slide 4 Visible | Visibility | — | Show or hide slide 4 | +| Slide 4 Image | Image | — | Slide 4 background or featured image | +| Slide 4 Title | Text | Seamless Integration | Slide 4 main heading text | +| Slide 4 Description | Text | Connect with your favorite... | Slide 4 descriptive text content | +| Slide 4 CTA Text | Text | Explore Integrations | Slide 4 call-to-action button text | +| Slide 4 CTA Link | Link | — | Slide 4 call-to-action button link | +| Slide 4 Show CTA | Boolean | true | Display the CTA button on slide 4 | +| Slide 5 Visible | Visibility | — | Show or hide slide 5 | +| Slide 5 Image | Image | — | Slide 5 background or featured image | +| Slide 5 Title | Text | Enterprise Ready | Slide 5 main heading text | +| Slide 5 Description | Text | Scale with confidence... | Slide 5 descriptive text content | +| Slide 5 CTA Text | Text | Contact Sales | Slide 5 call-to-action button text | +| Slide 5 CTA Link | Link | — | Slide 5 call-to-action button link | +| Slide 5 Show CTA | Boolean | true | Display the CTA button on slide 5 | +| Slide 6 Visible | Visibility | — | Show or hide slide 6 | +| Slide 6 Image | Image | — | Slide 6 background or featured image | +| Slide 6 Title | Text | 24/7 Support | Slide 6 main heading text | +| Slide 6 Description | Text | Our dedicated support team... | Slide 6 descriptive text content | +| Slide 6 CTA Text | Text | Get Support | Slide 6 call-to-action button text | +| Slide 6 CTA Link | Link | — | Slide 6 call-to-action button link | +| Slide 6 Show CTA | Boolean | true | Display the CTA button on slide 6 | +| Slide 7 Visible | Visibility | — | Show or hide slide 7 | +| Slide 7 Image | Image | — | Slide 7 background or featured image | +| Slide 7 Title | Text | Advanced Analytics | Slide 7 main heading text | +| Slide 7 Description | Text | Make data-driven decisions... | Slide 7 descriptive text content | +| Slide 7 CTA Text | Text | View Analytics | Slide 7 call-to-action button text | +| Slide 7 CTA Link | Link | — | Slide 7 call-to-action button link | +| Slide 7 Show CTA | Boolean | true | Display the CTA button on slide 7 | +| Slide 8 Visible | Visibility | — | Show or hide slide 8 | +| Slide 8 Image | Image | — | Slide 8 background or featured image | +| Slide 8 Title | Text | Mobile First | Slide 8 main heading text | +| Slide 8 Description | Text | Work from anywhere... | Slide 8 descriptive text content | +| Slide 8 CTA Text | Text | Download App | Slide 8 call-to-action button text | +| Slide 8 CTA Link | Link | — | Slide 8 call-to-action button link | +| Slide 8 Show CTA | Boolean | true | Display the CTA button on slide 8 | +| Slide 9 Visible | Visibility | — | Show or hide slide 9 | +| Slide 9 Image | Image | — | Slide 9 background or featured image | +| Slide 9 Title | Text | Customizable Workflows | Slide 9 main heading text | +| Slide 9 Description | Text | Adapt the platform... | Slide 9 descriptive text content | +| Slide 9 CTA Text | Text | Customize Now | Slide 9 call-to-action button text | +| Slide 9 CTA Link | Link | — | Slide 9 call-to-action button link | +| Slide 9 Show CTA | Boolean | true | Display the CTA button on slide 9 | +| Slide 10 Visible | Visibility | — | Show or hide slide 10 | +| Slide 10 Image | Image | — | Slide 10 background or featured image | +| Slide 10 Title | Text | Secure by Design | Slide 10 main heading text | +| Slide 10 Description | Text | Your data is protected... | Slide 10 descriptive text content | +| Slide 10 CTA Text | Text | Security Details | Slide 10 call-to-action button text | +| Slide 10 CTA Link | Link | — | Slide 10 call-to-action button link | +| Slide 10 Show CTA | Boolean | true | Display the CTA button on slide 10 | +| Slide 11 Visible | Visibility | — | Show or hide slide 11 | +| Slide 11 Image | Image | — | Slide 11 background or featured image | +| Slide 11 Title | Text | Collaborative Tools | Slide 11 main heading text | +| Slide 11 Description | Text | Bring your team together... | Slide 11 descriptive text content | +| Slide 11 CTA Text | Text | Start Collaborating | Slide 11 call-to-action button text | +| Slide 11 CTA Link | Link | — | Slide 11 call-to-action button link | +| Slide 11 Show CTA | Boolean | true | Display the CTA button on slide 11 | +| Slide 12 Visible | Visibility | — | Show or hide slide 12 | +| Slide 12 Image | Image | — | Slide 12 background or featured image | +| Slide 12 Title | Text | Start Your Journey | Slide 12 main heading text | +| Slide 12 Description | Text | Ready to transform... | Slide 12 descriptive text content | +| Slide 12 CTA Text | Text | Sign Up Free | Slide 12 call-to-action button text | +| Slide 12 CTA Link | Link | — | Slide 12 call-to-action button link | +| Slide 12 Show CTA | Boolean | true | Display the CTA button on slide 12 | + +## Styling + +This component automatically adapts to your Webflow site's design system through site variables and inherited properties. + +### Site Variables + +To match your site's design system, define these CSS variables in your Webflow project settings. The component will use the fallback values shown below until you configure them. + +| Site Variable | What It Controls | Fallback | +|---------------|------------------|----------| +| --background-primary | Slide card background and arrow button background | #ffffff | +| --background-secondary | Image placeholder background and arrow button hover states | #f5f5f5 | +| --text-primary | Slide titles and arrow icon color | #1a1a1a | +| --text-secondary | Slide descriptions and inactive dot hover color | #737373 | +| --border-color | Card borders, arrow button borders, and inactive dot color | #e5e5e5 | +| --accent-color | Active dot indicator and CTA button background | #1a1a1a | +| --accent-text-color | CTA button text color | #ffffff | +| --border-radius | Card and button corner rounding | 8px | + +### Inherited Properties + +The component inherits these CSS properties from its parent element: +- `font-family` — Typography style +- `color` — Text color +- `line-height` — Text spacing + +## Extending in Code + +### Custom Slide Navigation + +Access the carousel programmatically to create custom navigation controls: + +```javascript +const carousel = document.querySelector('[id="my-carousel"]'); +const nextButton = document.querySelector('#custom-next'); + +nextButton.addEventListener('click', () => { + // Trigger next slide programmatically + carousel.querySelector('.wf-carouselslider-arrow--next').click(); +}); +``` + +### Dynamic Slide Content + +Update slide content dynamically based on external data: + +```javascript +const updateSlide = (slideNumber, data) => { + const slide = document.querySelector(`[data-slide="${slideNumber}"]`); + slide.querySelector('.wf-carouselslider-title').textContent = data.title; + slide.querySelector('.wf-carouselslider-description').textContent = data.description; + slide.querySelector('.wf-carouselslider-image').src = data.imageUrl; +}; +``` + +## Dependencies + +No external dependencies. \ No newline at end of file diff --git a/carousel-slider/index.html b/carousel-slider/index.html new file mode 100644 index 0000000..1a419a9 --- /dev/null +++ b/carousel-slider/index.html @@ -0,0 +1,17 @@ + + + + + + CarouselSlider + + + +
+ + + diff --git a/carousel-slider/metadata.json b/carousel-slider/metadata.json new file mode 100644 index 0000000..cdb159e --- /dev/null +++ b/carousel-slider/metadata.json @@ -0,0 +1,5 @@ +{ + "name": "Carousel Slider", + "description": "Advanced carousel/slider with auto-play, dot indicators, swipe support, and configurable slide transitions.", + "category": "Data Display" +} diff --git a/carousel-slider/package.json b/carousel-slider/package.json new file mode 100644 index 0000000..5f93f4a --- /dev/null +++ b/carousel-slider/package.json @@ -0,0 +1,25 @@ +{ + "name": "carousel-slider", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.3", + "@webflow/data-types": "^1.0.1", + "@webflow/react": "^1.0.1", + "@webflow/webflow-cli": "^1.8.44", + "typescript": "~5.8.3", + "vite": "^7.1.7" + } +} \ No newline at end of file diff --git a/carousel-slider/screenshot-brand.jpg b/carousel-slider/screenshot-brand.jpg new file mode 100644 index 0000000..cd68d36 Binary files /dev/null and b/carousel-slider/screenshot-brand.jpg differ diff --git a/carousel-slider/screenshot-dark.jpg b/carousel-slider/screenshot-dark.jpg new file mode 100644 index 0000000..9e94bb3 Binary files /dev/null and b/carousel-slider/screenshot-dark.jpg differ diff --git a/carousel-slider/screenshot-light.jpg b/carousel-slider/screenshot-light.jpg new file mode 100644 index 0000000..b1e8f39 Binary files /dev/null and b/carousel-slider/screenshot-light.jpg differ diff --git a/carousel-slider/src/components/CarouselSlider/CarouselSlider.css b/carousel-slider/src/components/CarouselSlider/CarouselSlider.css new file mode 100644 index 0000000..eef7b65 --- /dev/null +++ b/carousel-slider/src/components/CarouselSlider/CarouselSlider.css @@ -0,0 +1,293 @@ +/* + * Webflow Site Variables Used: + * - --background-primary: Slide card background + * - --background-secondary: Arrow button hover states + * - --text-primary: Slide titles and main text + * - --text-secondary: Slide descriptions + * - --border-color: Card borders and dividers + * - --accent-color: Active dot, CTA button background + * - --accent-text-color: CTA button text + * - --border-radius: Card and button rounding + */ + +/* Box sizing reset */ +.wf-carouselslider *, +.wf-carouselslider *::before, +.wf-carouselslider *::after { + box-sizing: border-box; +} + +/* Root element - inherit typography + default padding */ +.wf-carouselslider { + font-family: inherit; + color: inherit; + line-height: inherit; + padding: 24px; + --wf-carouselslider-aspect-ratio: 56.25%; +} + +/* Empty state */ +.wf-carouselslider-empty { + padding: 48px 24px; + text-align: center; + color: var(--text-secondary, #737373); + background: var(--background-primary, #ffffff); + border: 1px solid var(--border-color, #e5e5e5); + border-radius: var(--border-radius, 8px); +} + +/* Container */ +.wf-carouselslider-container { + position: relative; + width: 100%; + overflow: hidden; + border-radius: var(--border-radius, 8px); +} + +.wf-carouselslider-container--peek { + padding: 0 48px; +} + +@media (max-width: 768px) { + .wf-carouselslider-container--peek { + padding: 0; + } +} + +/* Track */ +.wf-carouselslider-track { + display: flex; + width: 100%; + position: relative; +} + +.wf-carouselslider-track--slide { + transition: transform 0.5s ease-in-out; +} + +.wf-carouselslider-track--fade { + position: relative; +} + +/* Slide */ +.wf-carouselslider-slide { + flex: 0 0 100%; + width: 100%; + position: relative; +} + +.wf-carouselslider-track--fade .wf-carouselslider-slide { + position: absolute; + top: 0; + left: 0; + width: 100%; + opacity: 0; + transition: opacity 0.5s ease-in-out; + pointer-events: none; +} + +.wf-carouselslider-slide--active { + opacity: 1 !important; + pointer-events: auto; + position: relative !important; +} + +.wf-carouselslider-slide--inactive { + opacity: 0; + pointer-events: none; +} + +/* Slide content */ +.wf-carouselslider-slide-content { + background: var(--background-primary, #ffffff); + border: 1px solid var(--border-color, #e5e5e5); + border-radius: var(--border-radius, 8px); + overflow: hidden; + display: flex; + flex-direction: column; +} + +/* Image wrapper */ +.wf-carouselslider-image-wrapper { + position: relative; + width: 100%; + padding-bottom: var(--wf-carouselslider-aspect-ratio); + overflow: hidden; + background: var(--background-secondary, #f5f5f5); +} + +.wf-carouselslider-image { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; +} + +/* Text content */ +.wf-carouselslider-text-content { + padding: 32px; + display: flex; + flex-direction: column; + gap: 16px; +} + +@media (max-width: 768px) { + .wf-carouselslider-text-content { + padding: 24px; + } +} + +/* Title */ +.wf-carouselslider-title { + margin: 0; + font-size: 28px; + font-weight: 600; + line-height: 1.3; + color: var(--text-primary, #1a1a1a); +} + +@media (max-width: 768px) { + .wf-carouselslider-title { + font-size: 24px; + } +} + +/* Description */ +.wf-carouselslider-description { + margin: 0; + font-size: 16px; + line-height: 1.6; + color: var(--text-secondary, #737373); +} + +/* CTA button */ +.wf-carouselslider-cta { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 12px 24px; + background: var(--accent-color, #1a1a1a); + color: var(--accent-text-color, #ffffff); + text-decoration: none; + border-radius: var(--border-radius, 8px); + font-weight: 500; + font-size: 16px; + transition: opacity 0.2s, transform 0.2s; + align-self: flex-start; +} + +.wf-carouselslider-cta:hover { + opacity: 0.9; + transform: translateY(-1px); +} + +.wf-carouselslider-cta:active { + transform: translateY(0); +} + +.wf-carouselslider-cta:focus-visible { + outline: 2px solid var(--accent-color, #1a1a1a); + outline-offset: 2px; +} + +/* Navigation arrows */ +.wf-carouselslider-arrow { + position: absolute; + top: 50%; + transform: translateY(-50%); + background: var(--background-primary, #ffffff); + border: 1px solid var(--border-color, #e5e5e5); + border-radius: 50%; + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + z-index: 10; + transition: background-color 0.2s, border-color 0.2s; + padding: 0; +} + +.wf-carouselslider-arrow--prev { + left: 16px; +} + +.wf-carouselslider-arrow--next { + right: 16px; +} + +.wf-carouselslider-container--peek .wf-carouselslider-arrow--prev { + left: -8px; +} + +.wf-carouselslider-container--peek .wf-carouselslider-arrow--next { + right: -8px; +} + +.wf-carouselslider-arrow:hover { + background: var(--background-secondary, #f5f5f5); + border-color: var(--text-secondary, #737373); +} + +.wf-carouselslider-arrow:focus-visible { + outline: 2px solid var(--accent-color, #1a1a1a); + outline-offset: 2px; +} + +.wf-carouselslider-arrow:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.wf-carouselslider-arrow:disabled:hover { + background: var(--background-primary, #ffffff); + border-color: var(--border-color, #e5e5e5); +} + +.wf-carouselslider-arrow-icon { + width: 24px; + height: 24px; + color: var(--text-primary, #1a1a1a); +} + +/* Dots */ +.wf-carouselslider-dots { + display: flex; + justify-content: center; + gap: 8px; + margin-top: 24px; + padding: 0; +} + +.wf-carouselslider-dot { + width: 10px; + height: 10px; + border-radius: 50%; + background: var(--border-color, #e5e5e5); + border: none; + padding: 0; + cursor: pointer; + transition: background-color 0.2s, transform 0.2s; +} + +.wf-carouselslider-dot:hover { + background: var(--text-secondary, #737373); + transform: scale(1.2); +} + +.wf-carouselslider-dot:focus-visible { + outline: 2px solid var(--accent-color, #1a1a1a); + outline-offset: 2px; +} + +.wf-carouselslider-dot--active { + background: var(--accent-color, #1a1a1a); + transform: scale(1.2); +} + +.wf-carouselslider-dot--active:hover { + background: var(--accent-color, #1a1a1a); +} \ No newline at end of file diff --git a/carousel-slider/src/components/CarouselSlider/CarouselSlider.tsx b/carousel-slider/src/components/CarouselSlider/CarouselSlider.tsx new file mode 100644 index 0000000..72f4238 --- /dev/null +++ b/carousel-slider/src/components/CarouselSlider/CarouselSlider.tsx @@ -0,0 +1,426 @@ +import { useState, useEffect, useRef } from "react"; + +export interface CarouselSliderProps { + id?: string; + transitionEffect?: "slide" | "fade"; + aspectRatio?: "16:9" | "4:3" | "21:9" | "1:1" | "3:2"; + showPeek?: boolean; + autoPlay?: boolean; + autoPlayInterval?: number; + pauseOnHover?: boolean; + enableLoop?: boolean; + showArrows?: boolean; + showDots?: boolean; + slide1Visible?: boolean; + slide1Image?: string; + slide1Title?: string; + slide1Description?: string; + slide1CtaText?: string; + slide1CtaLink?: string; + slide1ShowCta?: boolean; + slide2Visible?: boolean; + slide2Image?: string; + slide2Title?: string; + slide2Description?: string; + slide2CtaText?: string; + slide2CtaLink?: string; + slide2ShowCta?: boolean; + slide3Visible?: boolean; + slide3Image?: string; + slide3Title?: string; + slide3Description?: string; + slide3CtaText?: string; + slide3CtaLink?: string; + slide3ShowCta?: boolean; + slide4Visible?: boolean; + slide4Image?: string; + slide4Title?: string; + slide4Description?: string; + slide4CtaText?: string; + slide4CtaLink?: string; + slide4ShowCta?: boolean; + slide5Visible?: boolean; + slide5Image?: string; + slide5Title?: string; + slide5Description?: string; + slide5CtaText?: string; + slide5CtaLink?: string; + slide5ShowCta?: boolean; + slide6Visible?: boolean; + slide6Image?: string; + slide6Title?: string; + slide6Description?: string; + slide6CtaText?: string; + slide6CtaLink?: string; + slide6ShowCta?: boolean; + slide7Visible?: boolean; + slide7Image?: string; + slide7Title?: string; + slide7Description?: string; + slide7CtaText?: string; + slide7CtaLink?: string; + slide7ShowCta?: boolean; + slide8Visible?: boolean; + slide8Image?: string; + slide8Title?: string; + slide8Description?: string; + slide8CtaText?: string; + slide8CtaLink?: string; + slide8ShowCta?: boolean; + slide9Visible?: boolean; + slide9Image?: string; + slide9Title?: string; + slide9Description?: string; + slide9CtaText?: string; + slide9CtaLink?: string; + slide9ShowCta?: boolean; + slide10Visible?: boolean; + slide10Image?: string; + slide10Title?: string; + slide10Description?: string; + slide10CtaText?: string; + slide10CtaLink?: string; + slide10ShowCta?: boolean; + slide11Visible?: boolean; + slide11Image?: string; + slide11Title?: string; + slide11Description?: string; + slide11CtaText?: string; + slide11CtaLink?: string; + slide11ShowCta?: boolean; + slide12Visible?: boolean; + slide12Image?: string; + slide12Title?: string; + slide12Description?: string; + slide12CtaText?: string; + slide12CtaLink?: string; + slide12ShowCta?: boolean; +} + +interface Slide { + visible: boolean; + image?: string; + title: string; + description: string; + ctaText: string; + ctaLink?: string; + showCta: boolean; +} + +export default function CarouselSlider({ + id, + transitionEffect = "slide", + aspectRatio = "16:9", + showPeek = false, + autoPlay = true, + autoPlayInterval = 5000, + pauseOnHover = true, + enableLoop = true, + showArrows = true, + showDots = true, + slide1Visible = true, + slide1Image, + slide1Title = "Discover Amazing Features", + slide1Description = "Experience the next generation of innovation with our cutting-edge solutions designed for modern businesses.", + slide1CtaText = "Learn More", + slide1CtaLink, + slide1ShowCta = true, + slide2Visible = true, + slide2Image, + slide2Title = "Built for Performance", + slide2Description = "Lightning-fast performance meets intuitive design. Get more done with tools that work as hard as you do.", + slide2CtaText = "Get Started", + slide2CtaLink, + slide2ShowCta = true, + slide3Visible = true, + slide3Image, + slide3Title = "Trusted by Thousands", + slide3Description = "Join thousands of satisfied customers who have transformed their workflow with our proven solutions.", + slide3CtaText = "View Testimonials", + slide3CtaLink, + slide3ShowCta = true, + slide4Visible = false, + slide4Image, + slide4Title = "Seamless Integration", + slide4Description = "Connect with your favorite tools and platforms. Our integrations make it easy to work the way you want.", + slide4CtaText = "Explore Integrations", + slide4CtaLink, + slide4ShowCta = true, + slide5Visible = false, + slide5Image, + slide5Title = "Enterprise Ready", + slide5Description = "Scale with confidence. Enterprise-grade security and support for organizations of any size.", + slide5CtaText = "Contact Sales", + slide5CtaLink, + slide5ShowCta = true, + slide6Visible = false, + slide6Image, + slide6Title = "24/7 Support", + slide6Description = "Our dedicated support team is always here to help. Get assistance whenever you need it, day or night.", + slide6CtaText = "Get Support", + slide6CtaLink, + slide6ShowCta = true, + slide7Visible = false, + slide7Image, + slide7Title = "Advanced Analytics", + slide7Description = "Make data-driven decisions with powerful analytics and insights that help you understand what matters most.", + slide7CtaText = "View Analytics", + slide7CtaLink, + slide7ShowCta = true, + slide8Visible = false, + slide8Image, + slide8Title = "Mobile First", + slide8Description = "Work from anywhere with our mobile-optimized platform. Full functionality on any device, anytime.", + slide8CtaText = "Download App", + slide8CtaLink, + slide8ShowCta = true, + slide9Visible = false, + slide9Image, + slide9Title = "Customizable Workflows", + slide9Description = "Adapt the platform to your unique processes. Create custom workflows that match your team's needs perfectly.", + slide9CtaText = "Customize Now", + slide9CtaLink, + slide9ShowCta = true, + slide10Visible = false, + slide10Image, + slide10Title = "Secure by Design", + slide10Description = "Your data is protected with industry-leading security measures. Compliance-ready and audit-friendly.", + slide10CtaText = "Security Details", + slide10CtaLink, + slide10ShowCta = true, + slide11Visible = false, + slide11Image, + slide11Title = "Collaborative Tools", + slide11Description = "Bring your team together with real-time collaboration features. Work smarter, not harder, together.", + slide11CtaText = "Start Collaborating", + slide11CtaLink, + slide11ShowCta = true, + slide12Visible = false, + slide12Image, + slide12Title = "Start Your Journey", + slide12Description = "Ready to transform your business? Join us today and experience the difference for yourself.", + slide12CtaText = "Sign Up Free", + slide12CtaLink, + slide12ShowCta = true, +}: CarouselSliderProps) { + const allSlides: Slide[] = [ + { visible: slide1Visible, image: slide1Image, title: slide1Title, description: slide1Description, ctaText: slide1CtaText, ctaLink: slide1CtaLink, showCta: slide1ShowCta }, + { visible: slide2Visible, image: slide2Image, title: slide2Title, description: slide2Description, ctaText: slide2CtaText, ctaLink: slide2CtaLink, showCta: slide2ShowCta }, + { visible: slide3Visible, image: slide3Image, title: slide3Title, description: slide3Description, ctaText: slide3CtaText, ctaLink: slide3CtaLink, showCta: slide3ShowCta }, + { visible: slide4Visible, image: slide4Image, title: slide4Title, description: slide4Description, ctaText: slide4CtaText, ctaLink: slide4CtaLink, showCta: slide4ShowCta }, + { visible: slide5Visible, image: slide5Image, title: slide5Title, description: slide5Description, ctaText: slide5CtaText, ctaLink: slide5CtaLink, showCta: slide5ShowCta }, + { visible: slide6Visible, image: slide6Image, title: slide6Title, description: slide6Description, ctaText: slide6CtaText, ctaLink: slide6CtaLink, showCta: slide6ShowCta }, + { visible: slide7Visible, image: slide7Image, title: slide7Title, description: slide7Description, ctaText: slide7CtaText, ctaLink: slide7CtaLink, showCta: slide7ShowCta }, + { visible: slide8Visible, image: slide8Image, title: slide8Title, description: slide8Description, ctaText: slide8CtaText, ctaLink: slide8CtaLink, showCta: slide8ShowCta }, + { visible: slide9Visible, image: slide9Image, title: slide9Title, description: slide9Description, ctaText: slide9CtaText, ctaLink: slide9CtaLink, showCta: slide9ShowCta }, + { visible: slide10Visible, image: slide10Image, title: slide10Title, description: slide10Description, ctaText: slide10CtaText, ctaLink: slide10CtaLink, showCta: slide10ShowCta }, + { visible: slide11Visible, image: slide11Image, title: slide11Title, description: slide11Description, ctaText: slide11CtaText, ctaLink: slide11CtaLink, showCta: slide11ShowCta }, + { visible: slide12Visible, image: slide12Image, title: slide12Title, description: slide12Description, ctaText: slide12CtaText, ctaLink: slide12CtaLink, showCta: slide12ShowCta }, + ]; + + const visibleSlides = allSlides.filter(slide => slide.visible); + const [currentIndex, setCurrentIndex] = useState(0); + const [isPaused, setIsPaused] = useState(false); + const [touchStart, setTouchStart] = useState(0); + const [touchEnd, setTouchEnd] = useState(0); + const containerRef = useRef(null); + + const aspectRatioMap: Record = { + "16:9": "56.25%", + "4:3": "75%", + "21:9": "42.86%", + "1:1": "100%", + "3:2": "66.67%", + }; + + const goToSlide = (index: number) => { + if (index < 0) { + setCurrentIndex(enableLoop ? visibleSlides.length - 1 : 0); + } else if (index >= visibleSlides.length) { + setCurrentIndex(enableLoop ? 0 : visibleSlides.length - 1); + } else { + setCurrentIndex(index); + } + }; + + const goToPrevious = () => { + goToSlide(currentIndex - 1); + }; + + const goToNext = () => { + goToSlide(currentIndex + 1); + }; + + useEffect(() => { + if (!autoPlay || isPaused || visibleSlides.length <= 1) return; + + const interval = setInterval(() => { + goToNext(); + }, autoPlayInterval); + + return () => clearInterval(interval); + }, [autoPlay, isPaused, currentIndex, autoPlayInterval, visibleSlides.length]); + + const handleTouchStart = (e: React.TouchEvent) => { + setTouchStart(e.targetTouches[0].clientX); + }; + + const handleTouchMove = (e: React.TouchEvent) => { + setTouchEnd(e.targetTouches[0].clientX); + }; + + const handleTouchEnd = () => { + if (!touchStart || !touchEnd) return; + + const distance = touchStart - touchEnd; + const isLeftSwipe = distance > 50; + const isRightSwipe = distance < -50; + + if (isLeftSwipe) { + goToNext(); + } else if (isRightSwipe) { + goToPrevious(); + } + + setTouchStart(0); + setTouchEnd(0); + }; + + const handleMouseEnter = () => { + if (pauseOnHover) { + setIsPaused(true); + } + }; + + const handleMouseLeave = () => { + if (pauseOnHover) { + setIsPaused(false); + } + }; + + if (visibleSlides.length === 0) { + return ( +
+
No slides to display
+
+ ); + } + + return ( +
+
+
+ {visibleSlides.map((slide, index) => ( +
+
+ {slide.image && ( +
+ {slide.title} +
+ )} +
+

{slide.title}

+

{slide.description}

+ {slide.showCta && ( + + {slide.ctaText} + + )} +
+
+
+ ))} +
+ + {showArrows && visibleSlides.length > 1 && ( + <> + + + + )} +
+ + {showDots && visibleSlides.length > 1 && ( +
+ {visibleSlides.map((_, index) => ( +
+ )} +
+ ); +} \ No newline at end of file diff --git a/carousel-slider/src/components/CarouselSlider/CarouselSlider.webflow.tsx b/carousel-slider/src/components/CarouselSlider/CarouselSlider.webflow.tsx new file mode 100644 index 0000000..6e72c23 --- /dev/null +++ b/carousel-slider/src/components/CarouselSlider/CarouselSlider.webflow.tsx @@ -0,0 +1,402 @@ +import CarouselSlider from "./CarouselSlider"; +import { props } from "@webflow/data-types"; +import { declareComponent } from "@webflow/react"; +import "./CarouselSlider.css"; + +export default declareComponent(CarouselSlider, { + name: "CarouselSlider", + description: "An advanced carousel component that displays one slide at a time with smooth transitions between slides. Each slide is a card containing an image, title, description, and optional CTA button with link. Features navigation arrows on both sides, dot indicators below for position tracking, and supports auto-play with pause-on-hover. Offers configurable transition effects (slide or fade), aspect ratios, and loop mode. Responsive design displays full-width slides on mobile and optionally shows a peek of adjacent slides on desktop. Supports touch/swipe gestures for mobile interaction and can accommodate 2-12 slides with individual visibility controls.", + group: "Interactive", + options: { + ssr: false, + applyTagSelectors: true + }, + props: { + id: props.Id({ + name: "Element ID", + group: "Settings", + tooltip: "HTML ID attribute for targeting and accessibility" + }), + transitionEffect: props.Variant({ + name: "Transition Effect", + options: ["slide", "fade"], + defaultValue: "slide", + group: "Behavior", + tooltip: "Animation style for slide transitions" + }), + aspectRatio: props.Variant({ + name: "Aspect Ratio", + options: ["16:9", "4:3", "21:9", "1:1", "3:2"], + defaultValue: "16:9", + group: "Style", + tooltip: "Slide container aspect ratio" + }), + showPeek: props.Boolean({ + name: "Show Peek", + defaultValue: false, + group: "Style", + tooltip: "Show peek of adjacent slides on desktop" + }), + autoPlay: props.Boolean({ + name: "Auto Play", + defaultValue: true, + group: "Behavior", + tooltip: "Enable automatic slide progression" + }), + autoPlayInterval: props.Number({ + name: "Auto Play Interval", + defaultValue: 5000, + group: "Behavior", + tooltip: "Milliseconds between auto-play transitions" + }), + pauseOnHover: props.Boolean({ + name: "Pause on Hover", + defaultValue: true, + group: "Behavior", + tooltip: "Pause auto-play when hovering over carousel" + }), + enableLoop: props.Boolean({ + name: "Enable Loop", + defaultValue: true, + group: "Behavior", + tooltip: "Loop from last slide back to first" + }), + showArrows: props.Boolean({ + name: "Show Arrows", + defaultValue: true, + group: "Display", + tooltip: "Display previous/next navigation arrows" + }), + showDots: props.Boolean({ + name: "Show Dots", + defaultValue: true, + group: "Display", + tooltip: "Display dot indicators below slides" + }), + slide1Visible: props.Visibility({ + name: "Visible", + group: "Slide 1", + tooltip: "Show or hide slide 1" + }), + slide1Image: props.Image({ + name: "Image", + group: "Slide 1", + tooltip: "Slide 1 background or featured image" + }), + slide1Title: props.Text({ + name: "Title", + defaultValue: "Discover Amazing Features", + group: "Slide 1", + tooltip: "Slide 1 main heading text" + }), + slide1Description: props.Text({ + name: "Description", + defaultValue: "Experience the next generation of innovation with our cutting-edge solutions designed for modern businesses.", + group: "Slide 1", + tooltip: "Slide 1 descriptive text content" + }), + slide1CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Learn More", + group: "Slide 1", + tooltip: "Slide 1 call-to-action button text" + }), + slide1CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 1", + tooltip: "Slide 1 call-to-action button link" + }), + slide1ShowCta: props.Boolean({ + name: "Show CTA", + defaultValue: true, + group: "Slide 1", + tooltip: "Display the CTA button on slide 1" + }), + slide2Visible: props.Visibility({ + name: "Visible", + group: "Slide 2", + tooltip: "Show or hide slide 2" + }), + slide2Image: props.Image({ + name: "Image", + group: "Slide 2", + tooltip: "Slide 2 background or featured image" + }), + slide2Title: props.Text({ + name: "Title", + defaultValue: "Built for Performance", + group: "Slide 2", + tooltip: "Slide 2 main heading text" + }), + slide2Description: props.Text({ + name: "Description", + defaultValue: "Lightning-fast performance meets intuitive design. Get more done with tools that work as hard as you do.", + group: "Slide 2", + tooltip: "Slide 2 descriptive text content" + }), + slide2CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Get Started", + group: "Slide 2", + tooltip: "Slide 2 call-to-action button text" + }), + slide2CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 2", + tooltip: "Slide 2 call-to-action button link" + }), + slide2ShowCta: props.Boolean({ + name: "Show CTA", + defaultValue: true, + group: "Slide 2", + tooltip: "Display the CTA button on slide 2" + }), + slide3Visible: props.Visibility({ + name: "Visible", + group: "Slide 3", + tooltip: "Show or hide slide 3" + }), + slide3Image: props.Image({ + name: "Image", + group: "Slide 3", + tooltip: "Slide 3 background or featured image" + }), + slide3Title: props.Text({ + name: "Title", + defaultValue: "Trusted by Thousands", + group: "Slide 3", + tooltip: "Slide 3 main heading text" + }), + slide3Description: props.Text({ + name: "Description", + defaultValue: "Join thousands of satisfied customers who have transformed their workflow with our proven solutions.", + group: "Slide 3", + tooltip: "Slide 3 descriptive text content" + }), + slide3CtaText: props.Text({ + name: "CTA Text", + defaultValue: "View Testimonials", + group: "Slide 3", + tooltip: "Slide 3 call-to-action button text" + }), + slide3CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 3", + tooltip: "Slide 3 call-to-action button link" + }), + slide3ShowCta: props.Boolean({ + name: "Show CTA", + defaultValue: true, + group: "Slide 3", + tooltip: "Display the CTA button on slide 3" + }), + slide4Visible: props.Visibility({ + name: "Visible", + group: "Slide 4", + tooltip: "Show or hide slide 4" + }), + slide4Image: props.Image({ + name: "Image", + group: "Slide 4", + tooltip: "Slide 4 background or featured image" + }), + slide4Title: props.Text({ + name: "Title", + defaultValue: "Seamless Integration", + group: "Slide 4", + tooltip: "Slide 4 main heading text" + }), + slide4Description: props.Text({ + name: "Description", + defaultValue: "Connect with your favorite tools and platforms. Our integrations make it easy to work the way you want.", + group: "Slide 4", + tooltip: "Slide 4 descriptive text content" + }), + slide4CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Explore Integrations", + group: "Slide 4", + tooltip: "Slide 4 call-to-action button text" + }), + slide4CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 4", + tooltip: "Slide 4 call-to-action button link" + }), + slide4ShowCta: props.Boolean({ + name: "Show CTA", + defaultValue: true, + group: "Slide 4", + tooltip: "Display the CTA button on slide 4" + }), + slide5Visible: props.Visibility({ + name: "Visible", + group: "Slide 5", + tooltip: "Show or hide slide 5" + }), + slide5Image: props.Image({ + name: "Image", + group: "Slide 5", + tooltip: "Slide 5 background or featured image" + }), + slide5Title: props.Text({ + name: "Title", + defaultValue: "Enterprise Ready", + group: "Slide 5", + tooltip: "Slide 5 main heading text" + }), + slide5Description: props.Text({ + name: "Description", + defaultValue: "Scale with confidence. Enterprise-grade security and support for organizations of any size.", + group: "Slide 5", + tooltip: "Slide 5 descriptive text content" + }), + slide5CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Contact Sales", + group: "Slide 5", + tooltip: "Slide 5 call-to-action button text" + }), + slide5CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 5", + tooltip: "Slide 5 call-to-action button link" + }), + slide5ShowCta: props.Boolean({ + name: "Show CTA", + defaultValue: true, + group: "Slide 5", + tooltip: "Display the CTA button on slide 5" + }), + slide6Visible: props.Visibility({ + name: "Visible", + group: "Slide 6", + tooltip: "Show or hide slide 6" + }), + slide6Image: props.Image({ + name: "Image", + group: "Slide 6", + tooltip: "Slide 6 background or featured image" + }), + slide6Title: props.Text({ + name: "Title", + defaultValue: "24/7 Support", + group: "Slide 6", + tooltip: "Slide 6 main heading text" + }), + slide6Description: props.Text({ + name: "Description", + defaultValue: "Our dedicated support team is always here to help. Get assistance whenever you need it, day or night.", + group: "Slide 6", + tooltip: "Slide 6 descriptive text content" + }), + slide6CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Get Support", + group: "Slide 6", + tooltip: "Slide 6 call-to-action button text" + }), + slide6CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 6", + tooltip: "Slide 6 call-to-action button link" + }), + slide6ShowCta: props.Boolean({ + name: "Show CTA", + defaultValue: true, + group: "Slide 6", + tooltip: "Display the CTA button on slide 6" + }), + slide7Visible: props.Visibility({ + name: "Visible", + group: "Slide 7", + tooltip: "Show or hide slide 7" + }), + slide7Image: props.Image({ + name: "Image", + group: "Slide 7", + tooltip: "Slide 7 background or featured image" + }), + slide7Title: props.Text({ + name: "Title", + defaultValue: "Advanced Analytics", + group: "Slide 7", + tooltip: "Slide 7 main heading text" + }), + slide7Description: props.Text({ + name: "Description", + defaultValue: "Make data-driven decisions with powerful analytics and insights that help you understand what matters most.", + group: "Slide 7", + tooltip: "Slide 7 descriptive text content" + }), + slide7CtaText: props.Text({ + name: "CTA Text", + defaultValue: "View Analytics", + group: "Slide 7", + tooltip: "Slide 7 call-to-action button text" + }), + slide7CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 7", + tooltip: "Slide 7 call-to-action button link" + }), + slide7ShowCta: props.Boolean({ + name: "Show CTA", + defaultValue: true, + group: "Slide 7", + tooltip: "Display the CTA button on slide 7" + }), + slide8Visible: props.Visibility({ + name: "Visible", + group: "Slide 8", + tooltip: "Show or hide slide 8" + }), + slide8Image: props.Image({ + name: "Image", + group: "Slide 8", + tooltip: "Slide 8 background or featured image" + }), + slide8Title: props.Text({ + name: "Title", + defaultValue: "Mobile First", + group: "Slide 8", + tooltip: "Slide 8 main heading text" + }), + slide8Description: props.Text({ + name: "Description", + defaultValue: "Work from anywhere with our mobile-optimized platform. Full functionality on any device, anytime.", + group: "Slide 8", + tooltip: "Slide 8 descriptive text content" + }), + slide8CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Download App", + group: "Slide 8", + tooltip: "Slide 8 call-to-action button text" + }), + slide8CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 8", + tooltip: "Slide 8 call-to-action button link" + }), + slide8ShowCta: props.Boolean({ + name: "Show CTA", + defaultValue: true, + group: "Slide 8", + tooltip: "Display the CTA button on slide 8" + }), + slide9Visible: props.Visibility({ + name: "Visible", + group: "Slide 9", + tooltip: "Show or hide slide 9" + }), + slide9Image: props.Image({ + name: "Image", + group: "Slide 9", + tooltip: "Slide 9 background or featured image" + }), + slide9Title: props.Text({ + name: "Title", + defaultValue: "Customizable Workflows", + group: "Slide 9", + tooltip: "Slide \ No newline at end of file diff --git a/carousel-slider/src/components/CarouselSlider/CarouselSliderSimple.webflow.tsx b/carousel-slider/src/components/CarouselSlider/CarouselSliderSimple.webflow.tsx new file mode 100644 index 0000000..525bdf5 --- /dev/null +++ b/carousel-slider/src/components/CarouselSlider/CarouselSliderSimple.webflow.tsx @@ -0,0 +1,183 @@ +import CarouselSlider from "./CarouselSlider"; +import { props } from "@webflow/data-types"; +import { declareComponent } from "@webflow/react"; +import "./CarouselSlider.css"; + +export default declareComponent(CarouselSlider, { + name: "CarouselSlider (Simple)", + description: "An advanced carousel component that displays one slide at a time with smooth transitions between slides. Each slide is a card containing an image, title, description, and optional CTA button with link. Features navigation arrows on both sides, dot indicators below for position tracking, and supports auto-play with pause-on-hover. Offers configurable transition effects (slide or fade), aspect ratios, and loop mode. Responsive design displays full-width slides on mobile and optionally shows a peek of adjacent slides on desktop. Supports touch/swipe gestures for mobile interaction and can accommodate 2-12 slides with individual visibility controls.", + group: "Interactive", + options: { + ssr: false, + applyTagSelectors: true + }, + props: { + id: props.Id({ + name: "Element ID", + group: "Settings", + tooltip: "HTML ID attribute for targeting and accessibility" + }), + slide1Visible: props.Visibility({ + name: "Visible", + group: "Slide 1", + tooltip: "Show or hide slide 1" + }), + slide1Image: props.Image({ + name: "Image", + group: "Slide 1", + tooltip: "Slide 1 background or featured image" + }), + slide1Title: props.Text({ + name: "Title", + defaultValue: "Discover Amazing Features", + group: "Slide 1", + tooltip: "Slide 1 main heading text" + }), + slide1CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Learn More", + group: "Slide 1", + tooltip: "Slide 1 call-to-action button text" + }), + slide1CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 1", + tooltip: "Slide 1 call-to-action button link" + }), + slide2Visible: props.Visibility({ + name: "Visible", + group: "Slide 2", + tooltip: "Show or hide slide 2" + }), + slide2Image: props.Image({ + name: "Image", + group: "Slide 2", + tooltip: "Slide 2 background or featured image" + }), + slide2Title: props.Text({ + name: "Title", + defaultValue: "Built for Performance", + group: "Slide 2", + tooltip: "Slide 2 main heading text" + }), + slide2CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Get Started", + group: "Slide 2", + tooltip: "Slide 2 call-to-action button text" + }), + slide2CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 2", + tooltip: "Slide 2 call-to-action button link" + }), + slide3Visible: props.Visibility({ + name: "Visible", + group: "Slide 3", + tooltip: "Show or hide slide 3" + }), + slide3Image: props.Image({ + name: "Image", + group: "Slide 3", + tooltip: "Slide 3 background or featured image" + }), + slide3Title: props.Text({ + name: "Title", + defaultValue: "Trusted by Thousands", + group: "Slide 3", + tooltip: "Slide 3 main heading text" + }), + slide3CtaText: props.Text({ + name: "CTA Text", + defaultValue: "View Testimonials", + group: "Slide 3", + tooltip: "Slide 3 call-to-action button text" + }), + slide3CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 3", + tooltip: "Slide 3 call-to-action button link" + }), + slide4Visible: props.Visibility({ + name: "Visible", + group: "Slide 4", + tooltip: "Show or hide slide 4" + }), + slide4Image: props.Image({ + name: "Image", + group: "Slide 4", + tooltip: "Slide 4 background or featured image" + }), + slide4Title: props.Text({ + name: "Title", + defaultValue: "Seamless Integration", + group: "Slide 4", + tooltip: "Slide 4 main heading text" + }), + slide4CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Explore Integrations", + group: "Slide 4", + tooltip: "Slide 4 call-to-action button text" + }), + slide4CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 4", + tooltip: "Slide 4 call-to-action button link" + }), + slide5Visible: props.Visibility({ + name: "Visible", + group: "Slide 5", + tooltip: "Show or hide slide 5" + }), + slide5Image: props.Image({ + name: "Image", + group: "Slide 5", + tooltip: "Slide 5 background or featured image" + }), + slide5Title: props.Text({ + name: "Title", + defaultValue: "Enterprise Ready", + group: "Slide 5", + tooltip: "Slide 5 main heading text" + }), + slide5CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Contact Sales", + group: "Slide 5", + tooltip: "Slide 5 call-to-action button text" + }), + slide5CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 5", + tooltip: "Slide 5 call-to-action button link" + }), + slide6Visible: props.Visibility({ + name: "Visible", + group: "Slide 6", + tooltip: "Show or hide slide 6" + }), + slide6Image: props.Image({ + name: "Image", + group: "Slide 6", + tooltip: "Slide 6 background or featured image" + }), + slide6Title: props.Text({ + name: "Title", + defaultValue: "24/7 Support", + group: "Slide 6", + tooltip: "Slide 6 main heading text" + }), + slide6CtaText: props.Text({ + name: "CTA Text", + defaultValue: "Get Support", + group: "Slide 6", + tooltip: "Slide 6 call-to-action button text" + }), + slide6CtaLink: props.Link({ + name: "CTA Link", + group: "Slide 6", + tooltip: "Slide 6 call-to-action button link" + }) + } +}); \ No newline at end of file diff --git a/carousel-slider/src/main.tsx b/carousel-slider/src/main.tsx new file mode 100644 index 0000000..741508a --- /dev/null +++ b/carousel-slider/src/main.tsx @@ -0,0 +1,326 @@ +import { StrictMode, useState } from "react"; +import { createRoot } from "react-dom/client"; +import CarouselSlider from "./components/CarouselSlider/CarouselSlider"; +import "./components/CarouselSlider/CarouselSlider.css"; + +type ThemeVars = { + "--background-primary": string; + "--background-secondary": string; + "--text-primary": string; + "--text-secondary": string; + "--border-color": string; + "--accent-color": string; + "--accent-text-color": string; + "--border-radius": string; +}; + +const lightTheme: ThemeVars = { + "--background-primary": "#ffffff", + "--background-secondary": "#f5f5f5", + "--text-primary": "#1a1a1a", + "--text-secondary": "#737373", + "--border-color": "#e5e5e5", + "--accent-color": "#2563eb", + "--accent-text-color": "#ffffff", + "--border-radius": "8px", +}; + +const darkTheme: ThemeVars = { + "--background-primary": "#0a0a0a", + "--background-secondary": "#1a1a1a", + "--text-primary": "#fafafa", + "--text-secondary": "#a3a3a3", + "--border-color": "#2a2a2a", + "--accent-color": "#3b82f6", + "--accent-text-color": "#ffffff", + "--border-radius": "8px", +}; + +const brandTheme: ThemeVars = { + "--background-primary": "#fef7f0", + "--background-secondary": "#fde8d0", + "--text-primary": "#1c1917", + "--text-secondary": "#78716c", + "--border-color": "#e7e5e4", + "--accent-color": "#ea580c", + "--accent-text-color": "#ffffff", + "--border-radius": "12px", +}; + +function App() { + const [activeTheme, setActiveTheme] = useState<"light" | "dark" | "brand" | "custom">("light"); + const [customVars, setCustomVars] = useState(lightTheme); + + const getCurrentTheme = (): ThemeVars => { + switch (activeTheme) { + case "light": + return lightTheme; + case "dark": + return darkTheme; + case "brand": + return brandTheme; + case "custom": + return customVars; + default: + return lightTheme; + } + }; + + const handleThemeChange = (theme: "light" | "dark" | "brand" | "custom") => { + setActiveTheme(theme); + if (theme !== "custom") { + const themeMap = { light: lightTheme, dark: darkTheme, brand: brandTheme }; + setCustomVars(themeMap[theme]); + } + }; + + const handleCustomVarChange = (key: keyof ThemeVars, value: string) => { + setCustomVars((prev) => ({ ...prev, [key]: value })); + }; + + const currentTheme = getCurrentTheme(); + const pageBackground = activeTheme === "dark" ? "#000000" : activeTheme === "brand" ? "#fef7f0" : "#f9fafb"; + + return ( +
+
+
+

+ CarouselSlider Component Preview +

+ +
+
+ + + + +
+ + {activeTheme === "custom" && ( +
+

+ Custom Theme Editor +

+
+ {(Object.keys(customVars) as Array).map((key) => ( +
+ + handleCustomVarChange(key, e.target.value)} + style={{ + width: "100%", + padding: "8px 12px", + border: `1px solid ${currentTheme["--border-color"]}`, + borderRadius: currentTheme["--border-radius"], + backgroundColor: currentTheme["--background-primary"], + color: currentTheme["--text-primary"], + fontSize: "14px", + boxSizing: "border-box", + }} + /> +
+ ))} +
+
+ )} +
+
+
+ +
+
+
+

+ Default Configuration +

+ +
+ +
+

+ Fade Transition with Peek View +

+ +
+ +
+

+ Square Aspect Ratio, No Auto-Play +

+ +
+
+
+
+ ); +} + +createRoot(document.getElementById("root")!).render( + + + +); \ No newline at end of file diff --git a/carousel-slider/src/vite-env.d.ts b/carousel-slider/src/vite-env.d.ts new file mode 100644 index 0000000..151aa68 --- /dev/null +++ b/carousel-slider/src/vite-env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file diff --git a/carousel-slider/tsconfig.app.json b/carousel-slider/tsconfig.app.json new file mode 100644 index 0000000..d775f2a --- /dev/null +++ b/carousel-slider/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsBuildInfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": [ + "ES2022", + "DOM", + "DOM.Iterable" + ], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/carousel-slider/tsconfig.json b/carousel-slider/tsconfig.json new file mode 100644 index 0000000..65f670c --- /dev/null +++ b/carousel-slider/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.node.json" + } + ] +} \ No newline at end of file diff --git a/carousel-slider/tsconfig.node.json b/carousel-slider/tsconfig.node.json new file mode 100644 index 0000000..c4a9a48 --- /dev/null +++ b/carousel-slider/tsconfig.node.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsBuildInfo", + "target": "ES2023", + "lib": [ + "ES2023" + ], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": [ + "vite.config.ts" + ] +} \ No newline at end of file diff --git a/carousel-slider/vite.config.ts b/carousel-slider/vite.config.ts new file mode 100644 index 0000000..c7a4f78 --- /dev/null +++ b/carousel-slider/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [react()], +}); \ No newline at end of file diff --git a/carousel-slider/webflow.json b/carousel-slider/webflow.json new file mode 100644 index 0000000..e784f93 --- /dev/null +++ b/carousel-slider/webflow.json @@ -0,0 +1,10 @@ +{ + "library": { + "name": "CarouselSlider", + "components": [ + "./src/**/*.webflow.@(js|jsx|mjs|ts|tsx)" + ], + "description": "An advanced carousel component that displays one slide at a time with smooth transitions between slides. Each slide is a card containing an image, title, description, and optional CTA button with link. Features navigation arrows on both sides, dot indicators below for position tracking, and supports auto-play with pause-on-hover. Offers configurable transition effects (slide or fade), aspect ratios, and loop mode. Responsive design displays full-width slides on mobile and optionally shows a peek of adjacent slides on desktop. Supports touch/swipe gestures for mobile interaction and can accommodate 2-12 slides with individual visibility controls.", + "id": "carousel-slider" + } +} \ No newline at end of file