diff --git a/.storybook/preview-body.html b/.storybook/preview-body.html
index 013c9defe..bbfeaafd3 100644
--- a/.storybook/preview-body.html
+++ b/.storybook/preview-body.html
@@ -1,12 +1,13 @@
diff --git a/src/components/RecentActivity/EnvironmentPanel/EnvironmentTab/styles.ts b/src/components/RecentActivity/EnvironmentPanel/EnvironmentTab/styles.ts
index 38b0d232f..74890a0b3 100644
--- a/src/components/RecentActivity/EnvironmentPanel/EnvironmentTab/styles.ts
+++ b/src/components/RecentActivity/EnvironmentPanel/EnvironmentTab/styles.ts
@@ -1,15 +1,13 @@
import styled from "styled-components";
import { ContainerProps } from "./types";
-export const Container = styled.button`
+export const Container = styled.li`
+ display: flex;
position: relative;
cursor: pointer;
- border: none;
- font-family: inherit;
font-weight: ${({ isSelected }) => (isSelected ? 700 : 500)};
font-size: 14px;
padding: 4px 12px;
- white-space: nowrap;
color: ${({ isSelected, theme }) => {
if (isSelected) {
@@ -48,6 +46,9 @@ export const Container = styled.button`
}
}};
+ border-bottom: ${({ isSelected }) =>
+ isSelected ? "1px solid #5154ec" : "none"};
+
&:hover {
font-weight: 700;
color: ${({ theme }) => {
@@ -62,11 +63,9 @@ export const Container = styled.button`
}};
}
- ${({ isSelected }) => {
- if (isSelected) {
- return `border-bottom: 1px solid #5154ec`;
- }
- }}
+ transition-property: color, font-weight, border;
+ transition-duration: 300ms;
+ transition-timing-function: ease-out;
`;
export const BadgeContainer = styled.div`
diff --git a/src/components/RecentActivity/EnvironmentPanel/index.tsx b/src/components/RecentActivity/EnvironmentPanel/index.tsx
index e89d3f293..a56ecca97 100644
--- a/src/components/RecentActivity/EnvironmentPanel/index.tsx
+++ b/src/components/RecentActivity/EnvironmentPanel/index.tsx
@@ -1,12 +1,31 @@
+import { useEffect, useState } from "react";
+import useDimensions from "react-cool-dimensions";
+import { DefaultTheme, useTheme } from "styled-components";
import { IconButton } from "../../common/IconButton";
+import { ChevronIcon } from "../../common/icons/ChevronIcon";
import { DigmaLogoFlatIcon } from "../../common/icons/DigmaLogoFlatIcon";
import { ListIcon } from "../../common/icons/ListIcon";
import { TableIcon } from "../../common/icons/TableIcon";
+import { DIRECTION } from "../../common/icons/types";
import { EnvironmentTab } from "./EnvironmentTab";
import * as s from "./styles";
-import { EnvironmentPanelProps } from "./types";
+import { EnvironmentPanelProps, ScrollDirection } from "./types";
+
+const getCarouselIconColor = (theme: DefaultTheme, isDisabled: boolean) => {
+ switch (theme.mode) {
+ case "light":
+ return isDisabled ? "#b9c0d4" : "#4d668a";
+ case "dark":
+ case "dark-jetbrains":
+ return isDisabled ? "#7c7c94" : "#e2e7ff";
+ }
+};
export const EnvironmentPanel = (props: EnvironmentPanelProps) => {
+ const theme = useTheme();
+ const [scrollLeft, setScrollLeft] = useState(0);
+ const { observe, width, entry } = useDimensions();
+
const handleEnvironmentTabClick = (name: string) => {
props.onEnvironmentSelect(name);
};
@@ -16,11 +35,55 @@ export const EnvironmentPanel = (props: EnvironmentPanelProps) => {
table: TableIcon
};
+ useEffect(() => {
+ if (entry) {
+ entry.target.scrollLeft = scrollLeft;
+ }
+ }, [entry, scrollLeft]);
+
const handleViewModeButtonClick = () => {
const mode = props.viewMode === "table" ? "list" : "table";
props.onViewModeChange(mode);
};
+ const handleCarouselButtonClick = (direction: ScrollDirection) => {
+ if (entry) {
+ let delta = width;
+ if (direction === "left") {
+ delta *= -1;
+ }
+
+ let newScrollLeft = entry.target.scrollLeft + delta;
+
+ if (newScrollLeft >= entry.target.scrollWidth - width) {
+ newScrollLeft = entry.target.scrollWidth - width;
+ }
+
+ if (newScrollLeft < 0) {
+ newScrollLeft = 0;
+ }
+
+ setScrollLeft(newScrollLeft);
+ }
+ };
+
+ const isCarouselButtonDisabled = (direction: ScrollDirection) => {
+ if (entry) {
+ if (direction === "left") {
+ return scrollLeft === 0;
+ }
+
+ if (direction === "right") {
+ return scrollLeft === entry.target.scrollWidth - width;
+ }
+ }
+
+ return false;
+ };
+
+ const isLeftCarouselButtonDisabled = isCarouselButtonDisabled("left");
+ const isRightCarouselButtonDisabled = isCarouselButtonDisabled("right");
+
return (
@@ -29,15 +92,37 @@ export const EnvironmentPanel = (props: EnvironmentPanelProps) => {
- {props.environments.map((environment) => (
- handleCarouselButtonClick("left")}
+ disabled={isLeftCarouselButtonDisabled}
+ >
+
+
+
+ {props.environments.map((environment) => (
+
+ ))}
+
+ handleCarouselButtonClick("right")}
+ disabled={isRightCarouselButtonDisabled}
+ >
+
- ))}
+
{
@@ -42,7 +41,7 @@ export const Container = styled.div`
align-items: center;
width: 100%;
height: 100%;
- gap: 12px;
+ gap: 4px;
background: ${({ theme }) => {
switch (theme.mode) {
case "light":
@@ -57,8 +56,28 @@ export const Container = styled.div`
border-radius: 8px;
position: relative;
box-sizing: border-box;
+`;
+
+export const EnvironmentList = styled.ul`
+ display: flex;
+ gap: 12px;
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+
+ scroll-behavior: smooth;
+`;
+
+export const CarouselButton = styled.button`
+ display: flex;
+ background: none;
+ padding: 0;
+ border: none;
+ cursor: pointer;
- flex-wrap: wrap;
+ &:disabled {
+ cursor: initial;
+ }
`;
const rotateAnimation = keyframes`
diff --git a/src/components/RecentActivity/EnvironmentPanel/types.ts b/src/components/RecentActivity/EnvironmentPanel/types.ts
index 3fdfd374a..08d9d5ac0 100644
--- a/src/components/RecentActivity/EnvironmentPanel/types.ts
+++ b/src/components/RecentActivity/EnvironmentPanel/types.ts
@@ -7,3 +7,5 @@ export interface EnvironmentPanelProps {
}
export type ViewMode = "table" | "list";
+
+export type ScrollDirection = "left" | "right";
diff --git a/src/components/common/ToggleSwitch/styles.ts b/src/components/common/ToggleSwitch/styles.ts
index 3683a8cbc..6fe33a2bf 100644
--- a/src/components/common/ToggleSwitch/styles.ts
+++ b/src/components/common/ToggleSwitch/styles.ts
@@ -27,8 +27,7 @@ export const SwitchContainer = styled.div`
border-radius: 8px;
width: 28px;
height: 16px;
- transition-property: background;
- transition-duration: 0.3s;
+ transition: background 300ms;
display: flex;
align-items: center;
@@ -48,7 +47,7 @@ export const Circle = styled.div`
height: 8px;
border-radius: 50%;
transition-property: background, margin-left;
- transition-duration: 0.3s;
+ transition-duration: 300ms;
margin-left: ${({ isChecked }) => (isChecked ? "16px" : "4px")};
background: ${({ isChecked, theme }) => {