From 980477ea845dfd6ed1bb9606a364cd383ac93e79 Mon Sep 17 00:00:00 2001
From: Martin Bittnerm <martin.bittner@yeebase.com>
Date: Thu, 16 Jan 2025 08:15:50 +0100
Subject: [PATCH 1/2] feat: allow icon button in carousel

---
 .../components/src/Carousel/Carousel.d.ts     |  1 +
 packages/components/src/Carousel/Carousel.tsx | 62 +++++++++++++++--
 .../components/content/carousel.stories.d.ts  |  2 +
 .../components/content/carousel.stories.tsx   | 66 +++++++++++++++++++
 4 files changed, 125 insertions(+), 6 deletions(-)

diff --git a/packages/components/src/Carousel/Carousel.d.ts b/packages/components/src/Carousel/Carousel.d.ts
index 59184596..9bad6146 100644
--- a/packages/components/src/Carousel/Carousel.d.ts
+++ b/packages/components/src/Carousel/Carousel.d.ts
@@ -15,6 +15,7 @@ export interface CarouselProps {
     hideNextButton?: boolean;
     hidePrevButton?: boolean;
     onChange?: (currentIndex: number) => void;
+    isIconButton?: boolean;
     children?: ReactNode;
 }
 declare const Carousel: React.FC<CarouselProps>;
diff --git a/packages/components/src/Carousel/Carousel.tsx b/packages/components/src/Carousel/Carousel.tsx
index 9f1ea0da..07d30c24 100644
--- a/packages/components/src/Carousel/Carousel.tsx
+++ b/packages/components/src/Carousel/Carousel.tsx
@@ -4,8 +4,15 @@ import { default as SlickSlider, ResponsiveObject } from 'react-slick';
 import styled from 'styled-components';
 import { display, layout, space } from 'styled-system';
 
+import {
+  MaterialCheck,
+  MaterialChevronLeft,
+  MaterialChevronRight,
+} from '@t3n/icons';
+
 import Box from '../Box';
 import Button from '../Button';
+import IconButton from '../IconButton';
 
 export interface CarouselProps {
   slidesToShow?: number;
@@ -22,6 +29,7 @@ export interface CarouselProps {
   hideNextButton?: boolean;
   hidePrevButton?: boolean;
   onChange?: (currentIndex: number) => void;
+  isIconButton?: boolean;
   children?: ReactNode;
 }
 
@@ -68,17 +76,43 @@ const StyledPrevButton = styled(Button)`
   ${({ theme }) => display({ theme, display: ['none', 'block'] })}
 `;
 
+const StyledIconButtonWrapper = styled.div<{ position: 'left' | 'right' }>`
+  position: absolute;
+  bottom: 0;
+  ${({ position }) => (position === 'left' ? 'left: 0;' : 'right: 0;')}
+  z-index: 1;
+`;
+
 const NextButton: React.FC<{
   onClick?: () => void;
   show: boolean;
-  label: string;
+  label?: string;
   customOnClick?: () => void;
-}> = ({ onClick, show = true, label, customOnClick }) => {
+  isIconButton?: boolean;
+  isLastSlide?: boolean;
+}> = ({
+  onClick,
+  show = true,
+  label,
+  customOnClick,
+  isIconButton,
+  isLastSlide,
+}) => {
   if (!show) return null;
 
+  const icon = isLastSlide ? MaterialCheck : MaterialChevronRight;
+
+  if (isIconButton) {
+    return (
+      <StyledIconButtonWrapper position="right">
+        <IconButton onClick={customOnClick || onClick} icon={icon} />
+      </StyledIconButtonWrapper>
+    );
+  }
+
   return (
     <StyledNextButton onClick={customOnClick || onClick}>
-      {label}
+      {isLastSlide ? 'Done' : label}
     </StyledNextButton>
   );
 };
@@ -86,11 +120,23 @@ const NextButton: React.FC<{
 const PrevButton: React.FC<{
   onClick?: () => void;
   show: boolean;
-  label: string;
+  label?: string;
   customOnClick?: () => void;
-}> = ({ onClick, show = true, label, customOnClick }) => {
+  isIconButton?: boolean;
+}> = ({ onClick, show = true, label, customOnClick, isIconButton }) => {
   if (!show) return null;
 
+  if (isIconButton) {
+    return (
+      <StyledIconButtonWrapper position="left">
+        <IconButton
+          onClick={customOnClick || onClick}
+          icon={MaterialChevronLeft}
+        />
+      </StyledIconButtonWrapper>
+    );
+  }
+
   return (
     <StyledPrevButton onClick={customOnClick || onClick} variant="secondary">
       {label}
@@ -112,6 +158,7 @@ const Carousel: React.FC<CarouselProps> = ({
   onPrevClick,
   hideNextButton,
   hidePrevButton,
+  isIconButton,
   onChange,
   children,
 }) => {
@@ -123,7 +170,7 @@ const Carousel: React.FC<CarouselProps> = ({
       onChange(currentIndex);
     }
   }, [currentIndex, onChange]);
-
+  const isLastSlide = currentIndex === slidesAmount - slidesToShow;
   return (
     <Box>
       <StyledSlider
@@ -141,6 +188,8 @@ const Carousel: React.FC<CarouselProps> = ({
                 ? !hideNextButton
                 : currentIndex < slidesAmount - 1 || infinite
             }
+            isLastSlide={isLastSlide}
+            isIconButton={isIconButton}
             label={nextLabel}
             customOnClick={onNextClick}
           />
@@ -152,6 +201,7 @@ const Carousel: React.FC<CarouselProps> = ({
                 ? !hidePrevButton
                 : currentIndex > 0 || infinite
             }
+            isIconButton={isIconButton}
             label={prevLabel}
             customOnClick={onPrevClick}
           />
diff --git a/packages/storybook/src/stories/components/content/carousel.stories.d.ts b/packages/storybook/src/stories/components/content/carousel.stories.d.ts
index e6c67d62..a94d279f 100644
--- a/packages/storybook/src/stories/components/content/carousel.stories.d.ts
+++ b/packages/storybook/src/stories/components/content/carousel.stories.d.ts
@@ -8,3 +8,5 @@ export declare const infinite: Story;
 export declare const autoplay: Story;
 export declare const responsive: Story;
 export declare const sliderInModal: Story;
+export declare const carouselWithChevronButtons: Story;
+export declare const sliderWithChevronButtonsInModal: Story;
diff --git a/packages/storybook/src/stories/components/content/carousel.stories.tsx b/packages/storybook/src/stories/components/content/carousel.stories.tsx
index 6279e018..e8c6d430 100644
--- a/packages/storybook/src/stories/components/content/carousel.stories.tsx
+++ b/packages/storybook/src/stories/components/content/carousel.stories.tsx
@@ -99,6 +99,7 @@ const meta: Meta<typeof Carousel> = {
     nextLabel: 'Nächste',
     prevLabel: 'Zurück',
     speed: 500,
+    isIconButton: false,
     children: defaultData.map((el) => (
       <Box key={el.id} mb={8} overflow="hidden">
         <Image
@@ -150,6 +151,12 @@ const StyledBox = styled(Box)`
 
 export const carousel: Story = {};
 
+export const carouselWithChevronButtons: Story = {
+  args: {
+    isIconButton: true,
+  },
+};
+
 export const infinite: Story = {
   args: {
     infinite: true,
@@ -257,3 +264,62 @@ export const sliderInModal: Story = {
     );
   },
 };
+
+export const sliderWithChevronButtonsInModal: Story = {
+  decorators: [storyContainerDecorator],
+  render: () => {
+    const [showOnboardingModal, setShowOnboardingModal] = useState(true);
+    const [currentIndex, setCurrentIndex] = useState(0);
+
+    return (
+      <>
+        <Button onClick={() => setShowOnboardingModal(true)}>
+          Slider im Modal anzeigen
+        </Button>
+
+        {showOnboardingModal && (
+          <StyledBox>
+            <Modal headline="" onClose={() => setShowOnboardingModal(false)}>
+              <Carousel
+                onNextClick={
+                  currentIndex === defaultData.length - 1
+                    ? () => setShowOnboardingModal(false)
+                    : undefined
+                }
+                isIconButton
+                hideNextButton={false}
+                nextLabel={
+                  currentIndex === defaultData.length - 1
+                    ? 'Schließen'
+                    : undefined
+                }
+                onChange={setCurrentIndex}
+              >
+                {defaultData.map((el) => (
+                  <Box key={el.id} mt={2} mb={8} overflow="hidden">
+                    <Image
+                      m="0 auto"
+                      height={['165px', '180px', '150px', '200px', '250px']}
+                      src={el.imageSrc}
+                      alt={el.headline}
+                      title={el.headline}
+                      lazy={false}
+                    />
+
+                    <Text bold mt={3} mb={2}>
+                      {el.name}
+                    </Text>
+                    <Heading as="h5" my={0}>
+                      {el.headline}
+                    </Heading>
+                    <Text>{el.description}</Text>
+                  </Box>
+                ))}
+              </Carousel>
+            </Modal>
+          </StyledBox>
+        )}
+      </>
+    );
+  },
+};

From d82269abf4e36ce438cee0c68896984c0d0dff70 Mon Sep 17 00:00:00 2001
From: Martin Bittnerm <martin.bittner@yeebase.com>
Date: Thu, 16 Jan 2025 08:18:39 +0100
Subject: [PATCH 2/2] fix: remove testing code

---
 packages/components/src/Carousel/Carousel.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/components/src/Carousel/Carousel.tsx b/packages/components/src/Carousel/Carousel.tsx
index 07d30c24..8f4f2b57 100644
--- a/packages/components/src/Carousel/Carousel.tsx
+++ b/packages/components/src/Carousel/Carousel.tsx
@@ -112,7 +112,7 @@ const NextButton: React.FC<{
 
   return (
     <StyledNextButton onClick={customOnClick || onClick}>
-      {isLastSlide ? 'Done' : label}
+      {label}
     </StyledNextButton>
   );
 };