diff --git a/package-lock.json b/package-lock.json index d7161abe3..ca99994d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,9 @@ "copy-to-clipboard": "^3.3.3", "date-fns": "^2.29.3", "react": "^18.2.0", + "react-cool-dimensions": "^3.0.1", "react-dom": "^18.2.0", + "react-transition-group": "^4.4.5", "styled-components": "^5.3.6" }, "devDependencies": { @@ -30,6 +32,7 @@ "@stylelint/postcss-css-in-js": "^0.38.0", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", + "@types/react-transition-group": "^4.4.5", "@types/styled-components": "^5.1.26", "@typescript-eslint/eslint-plugin": "^5.49.0", "@typescript-eslint/parser": "^5.49.0", @@ -2001,7 +2004,6 @@ "version": "7.7.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.13.2" } @@ -9286,6 +9288,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", @@ -13135,8 +13146,7 @@ "node_modules/csstype": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "node_modules/currently-unhandled": { "version": "0.4.1", @@ -13783,6 +13793,26 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dom-helpers/node_modules/@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -19485,7 +19515,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -20747,7 +20776,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -21011,6 +21039,14 @@ "node": ">=0.10.0" } }, + "node_modules/react-cool-dimensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/react-cool-dimensions/-/react-cool-dimensions-3.0.1.tgz", + "integrity": "sha512-DUsDB5WUN1Qh6fJJlBtqFKCktrZCPRYcVn8NTeM6hP/5AhZNjDOa2sC2Dg0EM3WUObPDNV5nFLA34vHQfahUeg==", + "peerDependencies": { + "react": ">= 16.8.0" + } + }, "node_modules/react-docgen": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", @@ -21136,6 +21172,21 @@ "node": ">=0.10.0" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -21285,8 +21336,7 @@ "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/regenerator-transform": { "version": "0.15.1", @@ -27309,7 +27359,6 @@ "version": "7.7.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz", "integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==", - "dev": true, "requires": { "regenerator-runtime": "^0.13.2" } @@ -32973,6 +33022,15 @@ "@types/react": "*" } }, + "@types/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", @@ -35998,8 +36056,7 @@ "csstype": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", - "dev": true + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "currently-unhandled": { "version": "0.4.1", @@ -36509,6 +36566,25 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + } + } + }, "dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -40923,8 +40999,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-copy": { "version": "0.1.0", @@ -41848,7 +41923,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -42051,6 +42125,12 @@ "loose-envify": "^1.1.0" } }, + "react-cool-dimensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/react-cool-dimensions/-/react-cool-dimensions-3.0.1.tgz", + "integrity": "sha512-DUsDB5WUN1Qh6fJJlBtqFKCktrZCPRYcVn8NTeM6hP/5AhZNjDOa2sC2Dg0EM3WUObPDNV5nFLA34vHQfahUeg==", + "requires": {} + }, "react-docgen": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.3.tgz", @@ -42149,6 +42229,17 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "dev": true }, + "react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -42269,8 +42360,7 @@ "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "regenerator-transform": { "version": "0.15.1", diff --git a/package.json b/package.json index 466b38c15..ffb062c2d 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@stylelint/postcss-css-in-js": "^0.38.0", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", + "@types/react-transition-group": "^4.4.5", "@types/styled-components": "^5.1.26", "@typescript-eslint/eslint-plugin": "^5.49.0", "@typescript-eslint/parser": "^5.49.0", @@ -77,7 +78,9 @@ "copy-to-clipboard": "^3.3.3", "date-fns": "^2.29.3", "react": "^18.2.0", + "react-cool-dimensions": "^3.0.1", "react-dom": "^18.2.0", + "react-transition-group": "^4.4.5", "styled-components": "^5.3.6" } } diff --git a/public/images/observabilityButton.gif b/public/images/observabilityButton.gif deleted file mode 100644 index 06f668ac0..000000000 Binary files a/public/images/observabilityButton.gif and /dev/null differ diff --git a/public/images/observabilityButton_dark.gif b/public/images/observabilityButton_dark.gif new file mode 100644 index 000000000..b1820b34b Binary files /dev/null and b/public/images/observabilityButton_dark.gif differ diff --git a/public/images/observabilityButton_light.gif b/public/images/observabilityButton_light.gif new file mode 100644 index 000000000..5d386766a Binary files /dev/null and b/public/images/observabilityButton_light.gif differ diff --git a/public/images/observabilityPanel.gif b/public/images/observabilityPanel_dark.gif similarity index 100% rename from public/images/observabilityPanel.gif rename to public/images/observabilityPanel_dark.gif diff --git a/public/images/observabilityPanel_light.gif b/public/images/observabilityPanel_light.gif new file mode 100644 index 000000000..4b69ad39a Binary files /dev/null and b/public/images/observabilityPanel_light.gif differ diff --git a/public/images/runOrDebug.gif b/public/images/runOrDebug_dark.gif similarity index 100% rename from public/images/runOrDebug.gif rename to public/images/runOrDebug_dark.gif diff --git a/public/images/runOrDebug_light.gif b/public/images/runOrDebug_light.gif new file mode 100644 index 000000000..78472bd80 Binary files /dev/null and b/public/images/runOrDebug_light.gif differ diff --git a/src/components/Assets/AssetList/index.tsx b/src/components/Assets/AssetList/index.tsx index 1f222355a..02055a5f3 100644 --- a/src/components/Assets/AssetList/index.tsx +++ b/src/components/Assets/AssetList/index.tsx @@ -1,11 +1,11 @@ import { useMemo, useState } from "react"; import { AssetEntry as AssetEntryComponent } from "../../common/AssetEntry"; -import { ChevronIcon } from "../../common/icons/ChevronIcon"; -import { DIRECTION } from "../../common/icons/types"; import { Menu } from "../../common/Menu"; import { Popover } from "../../common/Popover"; import { PopoverContent } from "../../common/Popover/PopoverContent"; import { PopoverTrigger } from "../../common/Popover/PopoverTrigger"; +import { ChevronIcon } from "../../common/icons/ChevronIcon"; +import { DIRECTION } from "../../common/icons/types"; import { getAssetTypeInfo } from "../utils"; import * as s from "./styles"; import { @@ -206,7 +206,8 @@ export const AssetList = (props: AssetListProps) => { ) : ( - Not seeing your data here? Maybe you’re missing some instrumentation! + Not seeing your data here? Maybe you're missing some + instrumentation! )} diff --git a/src/components/Assets/AssetList/styles.ts b/src/components/Assets/AssetList/styles.ts index 4fa0f6a49..292db193b 100644 --- a/src/components/Assets/AssetList/styles.ts +++ b/src/components/Assets/AssetList/styles.ts @@ -68,14 +68,6 @@ export const ListItem = styled.li` display: flex; `; -export const Link = styled.a` - color: #7891d0; - text-decoration: none; - font-weight: 500; - font-size: 12px; - line-height: 14px; -`; - export const NoDataText = styled.span` padding: 10px; font-weight: 500; diff --git a/src/components/InstallationWizard/Button/index.tsx b/src/components/InstallationWizard/Button/index.tsx deleted file mode 100644 index 919af10a7..000000000 --- a/src/components/InstallationWizard/Button/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import * as s from "./styles"; -import { ButtonProps } from "./types"; - -export const Button = (props: ButtonProps) => { - const handleClick = (e: React.MouseEvent) => { - if (props.onClick) { - props.onClick(e); - } - }; - - return ( - - - {props.icon} - {props.children} - - - ); -}; diff --git a/src/components/InstallationWizard/Button/styles.ts b/src/components/InstallationWizard/Button/styles.ts deleted file mode 100644 index c3a912e33..000000000 --- a/src/components/InstallationWizard/Button/styles.ts +++ /dev/null @@ -1,52 +0,0 @@ -import styled from "styled-components"; -import { ButtonProps } from "./types"; - -export const Button = styled.button` - font-weight: 500; - font-size: 12px; - line-height: 14px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 2px; - cursor: pointer; - color: #b9c2eb; - - padding: ${({ buttonType }) => - buttonType === "primary" ? "4px" : "2px 4px"}; - - background: ${({ buttonType }) => - buttonType === "primary" ? "#3538cd" : "none"}; - - border: ${({ buttonType }) => - buttonType === "primary" ? "none" : "1px solid #3538cd"}; - - width: ${({ buttonType }) => - buttonType === "primary" ? "100%" : "max-content"}; - - &:hover { - color: #dadada; - border: ${({ buttonType }) => - buttonType === "primary" ? "none" : "1px solid #5154ec"}; - background: ${({ buttonType }) => - buttonType === "primary" ? "#5154ec" : "none"}; - } - - &:focus { - color: #dadada; - background: ${({ buttonType }) => - buttonType === "primary" ? "#5154ec" : "none"}; - } - - &:disabled { - background: #2e2e2e; - color: #49494d; - cursor: initial; - } -`; - -export const ContentContainer = styled.div` - display: flex; - gap: 2px; - align-items: center; -`; diff --git a/src/components/InstallationWizard/Button/types.ts b/src/components/InstallationWizard/Button/types.ts deleted file mode 100644 index c09532888..000000000 --- a/src/components/InstallationWizard/Button/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ReactNode } from "react"; - -export interface ButtonProps { - icon?: ReactNode; - onClick?: React.MouseEventHandler; - disabled?: boolean; - children: React.ReactNode; - buttonType?: "primary" | "secondary"; - className?: string; -} diff --git a/src/components/InstallationWizard/CodeSnippet/index.tsx b/src/components/InstallationWizard/CodeSnippet/index.tsx index eeb7ca65e..8fda5767a 100644 --- a/src/components/InstallationWizard/CodeSnippet/index.tsx +++ b/src/components/InstallationWizard/CodeSnippet/index.tsx @@ -11,9 +11,13 @@ export const CodeSnippet = (props: CodeSnippetProps) => { return ( {props.text} - - - + ); }; diff --git a/src/components/InstallationWizard/CodeSnippet/styles.ts b/src/components/InstallationWizard/CodeSnippet/styles.ts index 60b1389ad..dfadde3a1 100644 --- a/src/components/InstallationWizard/CodeSnippet/styles.ts +++ b/src/components/InstallationWizard/CodeSnippet/styles.ts @@ -1,9 +1,9 @@ import styled from "styled-components"; import { getCodeFont } from "../../common/App/styles"; +import { FloatingIconButton } from "../../common/FloatingIconButton"; import { ContainerProps } from "./types"; export const Container = styled.div` - background: #252526; padding: 4px 4px 4px 8px; border-radius: 4px; display: flex; @@ -11,31 +11,40 @@ export const Container = styled.div` align-items: flex-start; justify-content: space-between; + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#e9eef4"; + case "dark": + case "dark-jetbrains": + return "#252526"; + } + }}; + ${({ disabled }) => (disabled ? "opacity: 0.5;" : "")} `; +// postcss-styled-components-disable-next-line export const Code = styled.code` ${({ theme }) => getCodeFont(theme.codeFont)} + font-weight: 500; font-size: 12px; line-height: 20px; letter-spacing: -0.1px; - color: #dadada; white-space: pre-wrap; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#828797"; + case "dark": + case "dark-jetbrains": + return "#dadada"; + } + }}; `; -export const CopyButton = styled.button` - padding: 0; - cursor: pointer; - box-sizing: border-box; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - width: 18px; - height: 18px; - background: #2e2e2e; - border: 1px solid #383838; - box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.25); - border-radius: 4px; +export const CopyButton = styled(FloatingIconButton)` + padding: 3px; `; diff --git a/src/components/InstallationWizard/FinishStep/index.tsx b/src/components/InstallationWizard/FinishStep/index.tsx index a8a8186b4..4d201c341 100644 --- a/src/components/InstallationWizard/FinishStep/index.tsx +++ b/src/components/InstallationWizard/FinishStep/index.tsx @@ -1,45 +1,56 @@ +import { DefaultTheme, useTheme } from "styled-components"; +import { getThemeKind } from "../../common/App/styles"; import { LightBulbIcon } from "../../common/icons/LightBulbIcon"; import { OpenTelemetryLogoIcon } from "../../common/icons/OpenTelemetryLogoIcon"; import { PlayIcon } from "../../common/icons/PlayIcon"; -import { SectionDescription, SectionIconContainer } from "../styles"; +import { SectionDescription } from "../styles"; import * as s from "./styles"; -export const FinishStep = () => ( - - - - - - Run / Debug your application - - - Run or debug your application and trigger some actions or APIs to collect - observability. - - - - - - - - - Observability Panel - - - You'll be able to see the results in the observability panel below, - you can open it by clicking on the "Telescope". - - - - - - - - - More and more information about your code will continue to appear as you - perform more actions. - - -); +const getTipIconColor = (theme: DefaultTheme): string => { + switch (theme.mode) { + case "light": + return "#788ca9"; + case "dark": + case "dark-jetbrains": + return "#b9c2eb"; + } +}; + +export const FinishStep = () => { + const theme = useTheme(); + const themeKind = getThemeKind(theme); + + return ( + + + Run / Debug your application + + + Run or debug your application and trigger some actions or APIs to + collect observability. + + + + + + Observability Panel + + + You'll be able to see the results in the observability panel below, + you can open it by clicking on the "Telescope". + + + + + + + + + More and more information about your code will continue to appear as you + perform more actions. + + + ); +}; diff --git a/src/components/InstallationWizard/FinishStep/styles.ts b/src/components/InstallationWizard/FinishStep/styles.ts index 789b31d4a..1b2637639 100644 --- a/src/components/InstallationWizard/FinishStep/styles.ts +++ b/src/components/InstallationWizard/FinishStep/styles.ts @@ -1,5 +1,6 @@ import styled from "styled-components"; -import * as s from "../styles"; +import { SectionTitle as CommonSectionTitle } from "../SectionTitle"; +import { IllustrationContainer as CommonIllustrationContainer } from "../styles"; export const Container = styled.div` display: flex; @@ -7,18 +8,16 @@ export const Container = styled.div` padding: 12px 8px; `; -export const SectionTitle = styled(s.SectionTitle)` +export const SectionTitle = styled(CommonSectionTitle)` gap: 8px; margin-bottom: 4px; `; -export const IllustrationContainer = styled(s.IllustrationContainer)` +export const IllustrationContainer = styled(CommonIllustrationContainer)` margin: 12px 0 12px; `; export const ObservabilityPanelIllustration = styled.img` - bottom: 0; - position: absolute; width: 100%; `; @@ -32,6 +31,20 @@ export const TipContainer = styled.div` gap: 4px; font-weight: 500; font-size: 12px; - color: #b9c2eb; margin-top: 8px; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#788ca9"; + case "dark": + case "dark-jetbrains": + return "#b9c2eb"; + } + }}; +`; + +export const TipIconContainer = styled.div` + display: flex; + flex-shrink: 0; `; diff --git a/src/components/InstallationWizard/InstallStep/index.tsx b/src/components/InstallationWizard/InstallStep/index.tsx index 4d3b605ea..72b68e36c 100644 --- a/src/components/InstallationWizard/InstallStep/index.tsx +++ b/src/components/InstallationWizard/InstallStep/index.tsx @@ -1,12 +1,13 @@ import { useState } from "react"; +import { useTheme } from "styled-components"; +import { getThemeKind } from "../../common/App/styles"; import { Loader } from "../../common/Loader"; import { CheckmarkCircleInvertedIcon } from "../../common/icons/CheckmarkCircleInvertedIcon"; import { CodeIcon } from "../../common/icons/CodeIcon"; import { DockerLogoIcon } from "../../common/icons/DockerLogoIcon"; -import { Button } from "../Button"; import { CodeSnippet } from "../CodeSnippet"; import { Tabs } from "../Tabs"; -import { Link, SectionDescription } from "../styles"; +import { Link, MainButton, SectionDescription } from "../styles"; import * as s from "./styles"; import { InstallStepProps } from "./types"; @@ -23,6 +24,7 @@ const DIGMA_HELM_CHART_URL = "https://github.com/digma-ai/helm-chart/tree/gh-pages"; export const InstallStep = (props: InstallStepProps) => { + const theme = useTheme(); const isConnectionCheckStarted = Boolean(props.connectionCheckStatus); const [selectedInstallTab, setSelectedInstallTab] = useState(0); const [selectedDockerComposeOSTab, setSelectedDockerComposeOSTab] = @@ -170,27 +172,34 @@ export const InstallStep = (props: InstallStepProps) => { /> {props.connectionCheckStatus && ( - + )} {!isConnectionCheckStarted && ( - + )} {props.connectionCheckStatus === "pending" && ( - + Complete )} {props.connectionCheckStatus === "failure" && ( - + Retry )} {props.connectionCheckStatus === "success" && ( - + )} ); diff --git a/src/components/InstallationWizard/InstallStep/styles.ts b/src/components/InstallationWizard/InstallStep/styles.ts index 18776a3d2..29f494f21 100644 --- a/src/components/InstallationWizard/InstallStep/styles.ts +++ b/src/components/InstallationWizard/InstallStep/styles.ts @@ -1,7 +1,7 @@ import styled from "styled-components"; -import { Button } from "../Button"; +import { Button } from "../../common/Button"; +import { SectionTitle as CommonSectionTitle } from "../SectionTitle"; import { Tabs } from "../Tabs"; -import * as s from "../styles"; export const Container = styled.div` display: flex; @@ -9,7 +9,7 @@ export const Container = styled.div` padding: 0 8px 12px; `; -export const SectionTitle = styled(s.SectionTitle)` +export const SectionTitle = styled(CommonSectionTitle)` gap: 2px; margin-bottom: 2px; `; diff --git a/src/components/InstallationWizard/ObservabilityStep/index.tsx b/src/components/InstallationWizard/ObservabilityStep/index.tsx index 78ed1d70c..1ff0dcfdd 100644 --- a/src/components/InstallationWizard/ObservabilityStep/index.tsx +++ b/src/components/InstallationWizard/ObservabilityStep/index.tsx @@ -1,10 +1,12 @@ import { useState } from "react"; +import { useTheme } from "styled-components"; +import { getThemeKind } from "../../common/App/styles"; import { Loader } from "../../common/Loader"; import { ToggleSwitch } from "../../common/ToggleSwitch"; import { OpenTelemetryLogoIcon } from "../../common/icons/OpenTelemetryLogoIcon"; -import { Button } from "../Button"; import { CodeSnippet } from "../CodeSnippet"; -import { Link, SectionDescription, SectionTitle } from "../styles"; +import { SectionTitle } from "../SectionTitle"; +import { Link, MainButton, SectionDescription } from "../styles"; import * as s from "./styles"; import { ObservabilityStepProps } from "./types"; @@ -18,6 +20,9 @@ traces: exporters: [otlp/digma, ...]`; export const ObservabilityStep = (props: ObservabilityStepProps) => { + const theme = useTheme(); + const themeKind = getThemeKind(theme); + const [isCollectorModified, setIsCollectorModified] = useState(false); @@ -25,10 +30,7 @@ export const ObservabilityStep = (props: ObservabilityStepProps) => { props.onGoToNextStep(); }; - const handleAlreadyUsingOTELLinkClick = ( - e: React.MouseEvent - ) => { - e.preventDefault(); + const handleAlreadyUsingOTELLinkClick = () => { props.onIsAlreadyUsingOtelChange(!props.isAlreadyUsingOtel); }; @@ -53,16 +55,16 @@ export const ObservabilityStep = (props: ObservabilityStepProps) => { /> {isCollectorModified ? ( - + ) : ( - + )} Observe your application @@ -79,7 +81,7 @@ export const ObservabilityStep = (props: ObservabilityStepProps) => { - To quickly collect data from your application in intelliJ, + To quickly collect data from your application in IntelliJ, You can just toggle observability on now to get started @@ -91,23 +93,23 @@ export const ObservabilityStep = (props: ObservabilityStepProps) => { {props.isObservabilityEnabled && ( - - Congratulation! + + Congratulations! Your application is now being observed. )} - You can always expand the Digma side-panel and open the settings menu as + You can always expand the Digma side panel and open the Settings menu as seen bellow - + Next Already using OpenTelemetry? diff --git a/src/components/InstallationWizard/ObservabilityStep/styles.ts b/src/components/InstallationWizard/ObservabilityStep/styles.ts index ee24d3b20..3305912d6 100644 --- a/src/components/InstallationWizard/ObservabilityStep/styles.ts +++ b/src/components/InstallationWizard/ObservabilityStep/styles.ts @@ -10,8 +10,6 @@ export const Container = styled.div` export const ObservabilityContainer = styled.div` padding: 20px; margin: 8px 0 12px; - background: #303031; - border: 1px solid #9b9b9b; box-sizing: border-box; border-radius: 4px; display: flex; @@ -21,24 +19,63 @@ export const ObservabilityContainer = styled.div` justify-content: center; user-select: none; cursor: pointer; + + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#e5eaf1"; + case "dark": + case "dark-jetbrains": + return "#303031"; + } + }}; + + border: 1px solid + ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#7891d0"; + case "dark": + case "dark-jetbrains": + return "#9b9b9b"; + } + }}; `; export const ObservabilityTitle = styled.span` font-weight: 500; font-size: 14px; text-transform: capitalize; - color: #fff; text-align: center; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#4d668a"; + case "dark": + case "dark-jetbrains": + return "#fff"; + } + }}; `; export const ObservabilityDescription = styled.div` font-weight: 500; font-size: 10px; line-height: 12px; - color: #969798; text-align: center; display: flex; flex-direction: column; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#828797"; + case "dark": + case "dark-jetbrains": + return "#969798"; + } + }}; `; export const ObservabilityToggleSwitchContainer = styled.div` @@ -54,19 +91,39 @@ export const CongratulationsTextContainer = styled.div` font-weight: 500; font-size: 10px; line-height: 11px; - color: #dadada; flex-wrap: wrap; justify-content: center; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#4d668a"; + case "dark": + case "dark-jetbrains": + return "#dadada"; + } + }}; `; export const CongratulationsText = styled.span` font-weight: 700; padding-left: 2px; - color: #67d28b; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#00c108"; + case "dark": + case "dark-jetbrains": + return "#67d28b"; + } + }}; `; export const IllustrationContainer = styled(s.IllustrationContainer)` margin-top: 8px; + display: flex; + justify-content: center; `; export const ObservabilityButtonIllustration = styled.img` diff --git a/src/components/InstallationWizard/SectionTitle/index.tsx b/src/components/InstallationWizard/SectionTitle/index.tsx new file mode 100644 index 000000000..1fec48cd6 --- /dev/null +++ b/src/components/InstallationWizard/SectionTitle/index.tsx @@ -0,0 +1,26 @@ +import { DefaultTheme, useTheme } from "styled-components"; +import * as s from "./styles"; +import { SectionTitleProps } from "./types"; + +const getIconColor = (theme: DefaultTheme): string => { + switch (theme.mode) { + case "light": + return "#4d668a"; + case "dark": + case "dark-jetbrains": + return "#fff"; + } +}; + +export const SectionTitle = (props: SectionTitleProps) => { + const theme = useTheme(); + + return ( + + + {props.icon && } + + {props.children} + + ); +}; diff --git a/src/components/InstallationWizard/SectionTitle/styles.ts b/src/components/InstallationWizard/SectionTitle/styles.ts new file mode 100644 index 000000000..761ed4f38 --- /dev/null +++ b/src/components/InstallationWizard/SectionTitle/styles.ts @@ -0,0 +1,24 @@ +import styled from "styled-components"; + +export const Container = styled.div` + display: flex; + font-weight: 500; + font-size: 14px; + align-items: center; + text-transform: capitalize; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#4d668a"; + case "dark": + case "dark-jetbrains": + return "#ededed"; + } + }}; +`; + +export const IconContainer = styled.div` + display: flex; + flex-shrink: 0; +`; diff --git a/src/components/InstallationWizard/SectionTitle/types.ts b/src/components/InstallationWizard/SectionTitle/types.ts new file mode 100644 index 000000000..23812c581 --- /dev/null +++ b/src/components/InstallationWizard/SectionTitle/types.ts @@ -0,0 +1,8 @@ +import { ComponentType, ReactNode } from "react"; +import { IconProps } from "../../common/icons/types"; + +export interface SectionTitleProps { + icon?: ComponentType; + children: ReactNode; + className?: string; +} diff --git a/src/components/InstallationWizard/Step/index.tsx b/src/components/InstallationWizard/Step/index.tsx new file mode 100644 index 000000000..12b674083 --- /dev/null +++ b/src/components/InstallationWizard/Step/index.tsx @@ -0,0 +1,104 @@ +import { useRef } from "react"; +import useDimensions from "react-cool-dimensions"; +import { CSSTransition } from "react-transition-group"; +import { useTheme } from "styled-components"; +import { CheckmarkCircleInvertedIcon } from "../../common/icons/CheckmarkCircleInvertedIcon"; +import * as s from "./styles"; +import { StepProps } from "./types"; + +const TRANSITION_CLASS_NAME = "step"; +const SKIP_LINK_TRANSITION_CLASS_NAME = "skip-link"; +const NUMBER_TRANSITION_CLASS_NAME = "number-link"; +const DEFAULT_TRANSITION_DURATION = 300; // in milliseconds + +export const Step = (props: StepProps) => { + const theme = useTheme(); + + const transitionDuration = + typeof props.transitionDuration === "number" + ? props.transitionDuration + : DEFAULT_TRANSITION_DURATION; + + const containerRef = useRef(null); + const skipLinkRef = useRef(null); + const numberRef = useRef(null); + + const { observe, height } = useDimensions(); + + const handleSkipLinkClick = () => { + props.onSkip(); + }; + + const isActive = props.status === "active"; + + return ( + + + + + + + + + {props.number} + + + + + {props.data.title} + + + Skip for now + + + + {props.data.content} + + + + ); +}; diff --git a/src/components/InstallationWizard/Step/styles.ts b/src/components/InstallationWizard/Step/styles.ts new file mode 100644 index 000000000..07ad1ab2f --- /dev/null +++ b/src/components/InstallationWizard/Step/styles.ts @@ -0,0 +1,195 @@ +import styled, { DefaultTheme } from "styled-components"; +import { Link } from "../styles"; +import { + ContainerProps, + HeaderProps, + NumberContainerProps, + NumberProps, + TransitionProps +} from "./types"; + +const HEADER_HEIGHT = 40; // in pixels; + +// postcss-styled-components-disable-next-line +export const Container = styled.div` + ${({ transitionClassName, transitionDuration, contentHeight }) => { + const totalHeight = HEADER_HEIGHT + contentHeight; + return ` + &.${transitionClassName}-enter { + height: ${HEADER_HEIGHT}px; + } + + &.${transitionClassName}-enter-active { + height: ${totalHeight}px; + transition: height ${transitionDuration}ms ease-out; + } + + &.${transitionClassName}-exit { + height: ${totalHeight}px; + } + + &.${transitionClassName}-exit-active { + height: ${HEADER_HEIGHT}px; + transition: height ${transitionDuration}ms ease-out; + } + `; + }}; + + height: ${({ status, contentHeight }) => + status === "active" + ? `${HEADER_HEIGHT + contentHeight}` + : `${HEADER_HEIGHT}`}px; + + overflow: hidden; +`; + +export const SkipLink = styled(Link)` + padding: 2px 4px; + font-weight: 400; + margin-left: auto; + + ${({ transitionClassName, transitionDuration }) => { + return ` + &.${transitionClassName}-enter { + opacity: 0; + } + + &.${transitionClassName}-enter-active { + opacity: 1; + transition: opacity ${transitionDuration}ms ease-out; + } + + &.${transitionClassName}-exit { + opacity: 1; + } + + &.${transitionClassName}-exit-active { + opacity: 0; + transition: opacity ${transitionDuration}ms ease-out; + } + `; + }} +`; + +export const Header = styled.div` + display: flex; + gap: 4px; + padding: 12px 8px; + font-weight: 500; + font-size: 14px; + text-transform: capitalize; + border-top: 1px solid + ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + }}; + height: ${HEADER_HEIGHT}px; + box-sizing: border-box; + + color: ${({ theme, status }) => { + switch (theme.mode) { + case "light": + return status === "active" ? "#4d668a" : "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return status === "active" ? "#fff" : "#9b9b9b"; + } + }}; + + transition: color ${({ transitionDuration }) => transitionDuration}ms ease-out; +`; + +export const NumberContainer = styled.div` + width: 18px; + height: 18px; + position: relative; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + + color: ${({ theme, isActive }) => { + switch (theme.mode) { + case "light": + return isActive ? "#f1f5fa" : "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return isActive ? "#fff" : "#383838"; + } + }}; + + transition-duration: ${({ transitionDuration }) => transitionDuration}ms; + transition-property: color; + transition-timing-function: ease-out; +`; + +export const getNumberBackgroundColor = (theme: DefaultTheme): string => { + switch (theme.mode) { + case "light": + return "#4d668a"; + case "dark": + case "dark-jetbrains": + return "#6a6dfa"; + } +}; + +export const Number = styled.span` + width: 100%; + height: 100%; + font-size: 14px; + line-height: 100%; + font-weight: 500; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + position: absolute; + + background: ${({ theme, status }) => + status === "completed" ? "none" : getNumberBackgroundColor(theme)}; + + ${({ theme, transitionClassName, transitionDuration }) => { + return ` + &.${transitionClassName}-enter { + background: none; + opacity: 0; + } + + &.${transitionClassName}-enter-active { + background: ${getNumberBackgroundColor(theme)}; + opacity: 1; + transition-property: opacity, background; + transition-duration: ${transitionDuration}ms; + transition-timing-function: ease-out; + } + + &.${transitionClassName}-exit { + background: ${getNumberBackgroundColor(theme)}; + opacity: 1; + } + + &.${transitionClassName}-exit-active { + background: none; + opacity: 0; + transition-property: opacity, background; + transition-duration: ${transitionDuration}ms; + transition-timing-function: ease-out; + } + `; + }} +`; + +export const ContentContainer = styled.div` + display: flex; + flex-direction: column; +`; + +export const Content = styled.div` + display: flex; + flex-direction: column; +`; diff --git a/src/components/InstallationWizard/Step/types.ts b/src/components/InstallationWizard/Step/types.ts new file mode 100644 index 000000000..241de9457 --- /dev/null +++ b/src/components/InstallationWizard/Step/types.ts @@ -0,0 +1,42 @@ +import { ReactNode } from "react"; + +export type StepStatus = "completed" | "active" | "not-completed"; + +export interface TransitionProps { + transitionClassName: string; + transitionDuration: number; +} + +export interface StepData { + title: string; + content: ReactNode; +} + +export interface StepProps { + data: StepData; + number: number; + status: StepStatus; + transitionDuration?: number; + onSkip: () => void; +} + +export interface ContainerProps { + status: StepStatus; + contentHeight: number; + transitionClassName: string; + transitionDuration: number; +} + +export interface HeaderProps { + status: StepStatus; + transitionDuration: number; +} + +export interface NumberContainerProps { + isActive: boolean; + transitionDuration: number; +} + +export interface NumberProps extends TransitionProps { + status: StepStatus; +} diff --git a/src/components/InstallationWizard/Tabs/Tab/index.tsx b/src/components/InstallationWizard/Tabs/Tab/index.tsx new file mode 100644 index 000000000..28b521d23 --- /dev/null +++ b/src/components/InstallationWizard/Tabs/Tab/index.tsx @@ -0,0 +1,84 @@ +import { useCallback, useState } from "react"; +import { DefaultTheme, useTheme } from "styled-components"; +import * as s from "./styles"; +import { TabProps } from "./types"; + +const getIconColor = ( + theme: DefaultTheme, + isDisabled: boolean, + isHovered: boolean, + isFocused: boolean, + isSelected: boolean +): string => { + if (isDisabled) { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + } + + if (isSelected || isFocused || isHovered) { + switch (theme.mode) { + case "light": + return "#002d61"; + case "dark": + case "dark-jetbrains": + return "#dadada"; + } + } + + switch (theme.mode) { + case "light": + return "#828797"; + case "dark": + case "dark-jetbrains": + return "#9b9b9b"; + } +}; + +export const Tab = (props: TabProps) => { + const theme = useTheme(); + + const [isHovered, setIsHovered] = useState(false); + const [isFocused, setIsFocused] = useState(false); + + const handleMouseEnter = useCallback(() => setIsHovered(true), []); + const handleMouseLeave = useCallback(() => setIsHovered(false), []); + + const handleFocus = useCallback(() => setIsFocused(true), []); + const handleBlur = useCallback(() => setIsFocused(false), []); + + const handleContainerClick = () => { + if (!props.isDisabled) { + props.onClick(); + } + }; + return ( + + {props.icon && ( + + )} + {props.children} + + ); +}; diff --git a/src/components/InstallationWizard/Tabs/Tab/styles.ts b/src/components/InstallationWizard/Tabs/Tab/styles.ts new file mode 100644 index 000000000..1e56bdd95 --- /dev/null +++ b/src/components/InstallationWizard/Tabs/Tab/styles.ts @@ -0,0 +1,41 @@ +import styled from "styled-components"; +import { TabProps } from "./types"; + +export const Container = styled.li` + box-sizing: border-box; + font-weight: 500; + font-size: 12px; + line-height: 14px; + padding: 9px 10px; + display: flex; + gap: 4px; + user-select: none; + + cursor: ${({ isDisabled }) => (isDisabled ? "initial" : "pointer")}; + + border-bottom: ${({ isSelected }) => + isSelected ? "3px solid #5154ec" : "none"}; + + color: ${({ theme, isSelected, isDisabled }) => { + switch (theme.mode) { + case "light": + return isDisabled ? "#b9c0d4" : isSelected ? "#002d61" : "#828797"; + case "dark": + case "dark-jetbrains": + return isDisabled ? "#49494d" : isSelected ? "#dadada" : "#9b9b9b"; + } + }}; + + &:hover, + &:focus { + color: ${({ theme, isDisabled }) => { + switch (theme.mode) { + case "light": + return isDisabled ? "#b9c0d4" : "#002d61"; + case "dark": + case "dark-jetbrains": + return isDisabled ? "#49494d" : "#dadada"; + } + }}; + } +`; diff --git a/src/components/InstallationWizard/Tabs/Tab/types.ts b/src/components/InstallationWizard/Tabs/Tab/types.ts new file mode 100644 index 000000000..ab23d0887 --- /dev/null +++ b/src/components/InstallationWizard/Tabs/Tab/types.ts @@ -0,0 +1,10 @@ +import { ComponentType, ReactNode } from "react"; +import { IconProps } from "../../../common/icons/types"; + +export interface TabProps { + isSelected: boolean; + isDisabled?: boolean; + onClick: () => void; + icon?: ComponentType; + children: ReactNode; +} diff --git a/src/components/InstallationWizard/Tabs/index.tsx b/src/components/InstallationWizard/Tabs/index.tsx index 858ed61ea..09532585d 100644 --- a/src/components/InstallationWizard/Tabs/index.tsx +++ b/src/components/InstallationWizard/Tabs/index.tsx @@ -1,11 +1,10 @@ +import { Tab } from "./Tab"; import * as s from "./styles"; import { TabsProps } from "./types"; export const Tabs = (props: TabsProps) => { const handleTabClick = (tabIndex: number) => { - if (!props.tabs[tabIndex].disabled) { - props.onSelect(tabIndex); - } + props.onSelect(tabIndex); }; return ( @@ -15,20 +14,15 @@ export const Tabs = (props: TabsProps) => { const isSelected = props.selectedTab === i; return ( - handleTabClick(i)} + icon={tab.icon} > - {tab.icon && ( - - )} {tab.title} - + ); })} diff --git a/src/components/InstallationWizard/Tabs/styles.ts b/src/components/InstallationWizard/Tabs/styles.ts index ce90a4868..c1a749bb3 100644 --- a/src/components/InstallationWizard/Tabs/styles.ts +++ b/src/components/InstallationWizard/Tabs/styles.ts @@ -1,5 +1,4 @@ import styled from "styled-components"; -import { TabProps } from "./types"; export const Container = styled.div` display: flex; @@ -12,21 +11,15 @@ export const TabList = styled.ul` margin: 0; padding: 0; box-sizing: border-box; - border-bottom: 1px solid #2e2e2e; -`; - -export const Tab = styled.li` - box-sizing: border-box; - font-weight: 500; - font-size: 12px; - line-height: 14px; - padding: 9px 10px; - display: flex; - gap: 4px; - cursor: ${({ disabled }) => (disabled ? "initial" : "pointer")}; - - border-bottom: ${({ isSelected }) => - isSelected ? "3px solid #5154ec" : "none"}; - color: ${({ isSelected }) => (isSelected ? "#dadada" : "#9b9b9b")}; + border-bottom: 1px solid + ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#2e2e2e"; + } + }}; `; diff --git a/src/components/InstallationWizard/Tabs/types.ts b/src/components/InstallationWizard/Tabs/types.ts index 196e05ef2..c887cc7d7 100644 --- a/src/components/InstallationWizard/Tabs/types.ts +++ b/src/components/InstallationWizard/Tabs/types.ts @@ -12,8 +12,3 @@ export interface TabsProps { onSelect: (tabIndex: number) => void; className?: string; } - -export interface TabProps { - isSelected: boolean; - disabled?: boolean; -} diff --git a/src/components/InstallationWizard/index.tsx b/src/components/InstallationWizard/index.tsx index 5ff6042b1..0504fcdcb 100644 --- a/src/components/InstallationWizard/index.tsx +++ b/src/components/InstallationWizard/index.tsx @@ -1,13 +1,14 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; +import { CSSTransition } from "react-transition-group"; import { dispatcher } from "../../dispatcher"; import { usePrevious } from "../../hooks/usePrevious"; import { addPrefix } from "../../utils/addPrefix"; import { actions as globalActions } from "../common/App"; -import { CheckmarkCircleInvertedIcon } from "../common/icons/CheckmarkCircleInvertedIcon"; -import { Button } from "./Button"; import { FinishStep } from "./FinishStep"; import { InstallStep } from "./InstallStep"; import { ObservabilityStep } from "./ObservabilityStep"; +import { Step } from "./Step"; +import { StepData, StepStatus } from "./Step/types"; import * as s from "./styles"; import { ConnectionCheckResultData, ConnectionCheckStatus } from "./types"; @@ -37,17 +38,32 @@ const trackingEvents = addPrefix( " " ); +const footerTransitionClassName = "footer"; +const TRANSITION_DURATION = 300; // in milliseconds + const firstStep = window.wizardSkipInstallationStep === true ? 1 : 0; +const getStepStatus = (index: number, currentStep: number): StepStatus => { + if (index < currentStep) { + return "completed"; + } + + if (index === currentStep) { + return "active"; + } + + return "not-completed"; +}; + export const InstallationWizard = () => { const [currentStep, setCurrentStep] = useState(firstStep); const previousStep = usePrevious(currentStep); const [isAlreadyUsingOtel, setIsAlreadyUsingOtel] = useState(false); const [isObservabilityEnabled, setIsObservabilityEnabled] = useState(false); - const [connectionCheckStatus, setConnectionCheckStatus] = useState(); + const footerContentRef = useRef(null); useEffect(() => { if (previousStep === 0 && currentStep === 1) { @@ -140,8 +156,7 @@ export const InstallationWizard = () => { } }; - const handleSkipLinkClick = (e: React.MouseEvent) => { - e.preventDefault(); + const handleSkipStep = () => { if (currentStep < steps.length - 1) { setCurrentStep(currentStep + 1); } else { @@ -157,7 +172,7 @@ export const InstallationWizard = () => { }); }; - const steps = [ + const steps: StepData[] = [ { title: "Get Digma up and running", content: ( @@ -192,10 +207,6 @@ export const InstallationWizard = () => { } ]; - const step = steps[currentStep]; - const previousSteps = steps.slice(0, currentStep); - const nextSteps = steps.slice(currentStep + 1); - return ( @@ -204,32 +215,34 @@ export const InstallationWizard = () => { Follow the steps to configure your projects - {previousSteps.length > 0 && - previousSteps.map((step) => ( - - - {step.title} - - ))} - - - {currentStep + 1} - {step.title} - Skip for now - - {step.content} - - {nextSteps.length > 0 && - nextSteps.map((step, i) => ( - - {currentStep + 2 + i} - {step.title} - - ))} + {steps.map((step, i) => ( + + ))} - {currentStep === steps.length - 1 && ( - - )} + + + + Finish + + + ); diff --git a/src/components/InstallationWizard/styles.ts b/src/components/InstallationWizard/styles.ts index db4360afb..f9557f6a4 100644 --- a/src/components/InstallationWizard/styles.ts +++ b/src/components/InstallationWizard/styles.ts @@ -1,10 +1,21 @@ import styled from "styled-components"; +import { Button } from "../common/Button"; +import { Link as CommonLink } from "../common/Link"; export const Container = styled.div` - background: #383838; min-height: 100vh; display: flex; flex-direction: column; + + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#383838"; + } + }}; `; export const Header = styled.div` @@ -12,9 +23,27 @@ export const Header = styled.div` text-align: center; font-weight: 500; font-size: 12px; - color: #fff; - background: #2e2e2e; padding: 8px; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#fbfdff"; + case "dark": + case "dark-jetbrains": + return "#fff"; + } + }}; + + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#788ca9"; + case "dark": + case "dark-jetbrains": + return "#2e2e2e"; + } + }}; `; export const HeaderTitle = styled.span` @@ -23,107 +52,111 @@ export const HeaderTitle = styled.span` export const HeaderSubtitle = styled.span` padding-left: 8px; - color: #9b9b9b; - border-left: 1px solid #7c7c94; -`; - -export const Link = styled.a` + border-left: 1px solid + ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#fbfdff"; + case "dark": + case "dark-jetbrains": + return "#7c7c94"; + } + }}; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#9b9b9b"; + } + }}; +`; + +export const Link = styled(CommonLink)` font-size: 12px; line-height: 14px; - color: #b9c2eb; - text-decoration: underline; - cursor: pointer; -`; - -export const SkipLink = styled(Link)` - padding: 2px 4px; - margin-left: auto; - font-weight: 400; -`; - -export const StepHeader = styled.div` - display: flex; - gap: 4px; - padding: 12px 8px; - color: #fff; - font-weight: 500; - font-size: 14px; - text-transform: capitalize; - border-top: 1px solid #49494d; -`; - -export const InactiveStepHeader = styled(StepHeader)` - color: #9b9b9b; -`; - -export const Content = styled.div` - display: flex; - flex-direction: column; `; export const Footer = styled.div` - background: #3d3f41; display: flex; flex-grow: 1; - flex-direction: column; - align-items: center; - justify-content: flex-end; - margin-top: auto; padding: 12px; -`; -export const StepNumber = styled.div` - display: flex; - align-items: center; - justify-content: center; - width: 18px; - height: 18px; - background: #6a6dfa; - border-radius: 50%; - font-size: 14px; - line-height: 100%; - font-weight: 500; - color: #fff; - flex-shrink: 0; -`; - -export const NextStepNumber = styled(StepNumber)` - color: #383838; -`; - -export const StepContent = styled.div` + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#fbfdff"; + case "dark": + case "dark-jetbrains": + return "#3d3f41"; + } + }}; +`; + +// postcss-styled-components-disable-next-line +export const FooterContent = styled.div<{ + transitionClassName: string; + transitionDuration: number; +}>` display: flex; flex-direction: column; - flex-grow: 1; -`; - -export const SectionTitle = styled.div` - display: flex; - font-weight: 500; - font-size: 14px; - color: #ededed; align-items: center; - text-transform: capitalize; -`; + flex-grow: 1; + justify-content: flex-end; -export const SectionIconContainer = styled.div` - display: flex; - flex-shrink: 0; + ${({ transitionClassName, transitionDuration }) => { + return ` + &.${transitionClassName}-enter { + opacity: 0; + } + + &.${transitionClassName}-enter-active { + opacity: 1; + transition: opacity ${transitionDuration}ms ease-out; + } + `; + }}; `; export const SectionDescription = styled.span` font-size: 12px; - color: #9b9b9b; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#828797"; + case "dark": + case "dark-jetbrains": + return "#9b9b9b"; + } + }}; `; export const IllustrationContainer = styled.div` height: 123px; width: 312px; - background: #313131; - border-radius 4px; - position: relative; + border-radius: 4px; overflow: hidden; display: flex; align-items: center; justify-content: center; + + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#dfe6f0"; + case "dark": + case "dark-jetbrains": + return "#313131"; + } + }}; +`; + +export const MainButton = styled(Button)` + padding: 4px; + font-size: 12px; + line-height: 14px; + width: 100%; `; diff --git a/src/components/RecentActivity/RecentActivityTable/SpanLink/index.tsx b/src/components/RecentActivity/RecentActivityTable/SpanLink/index.tsx deleted file mode 100644 index e61be76e0..000000000 --- a/src/components/RecentActivity/RecentActivityTable/SpanLink/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import * as s from "./styles"; -import { LinkProps } from "./types"; - -export const SpanLink = (props: LinkProps) => { - const handleClick = () => { - props.onClick(); - }; - - return {props.text}; -}; diff --git a/src/components/RecentActivity/RecentActivityTable/SpanLink/styles.ts b/src/components/RecentActivity/RecentActivityTable/SpanLink/styles.ts deleted file mode 100644 index 2a6c0cc22..000000000 --- a/src/components/RecentActivity/RecentActivityTable/SpanLink/styles.ts +++ /dev/null @@ -1,17 +0,0 @@ -import styled from "styled-components"; -import { getCodeFont } from "../../../common/App/styles"; - -export const Link = styled.a` - ${({ theme }) => getCodeFont(theme.codeFont)} - color: ${({ theme }) => { - switch (theme.mode) { - case "light": - return "#426dda"; - case "dark": - case "dark-jetbrains": - return "#7891d0"; - } - }}; - font-size: 12px; - cursor: pointer; -`; diff --git a/src/components/RecentActivity/RecentActivityTable/SpanLink/types.ts b/src/components/RecentActivity/RecentActivityTable/SpanLink/types.ts deleted file mode 100644 index 402adfe70..000000000 --- a/src/components/RecentActivity/RecentActivityTable/SpanLink/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface LinkProps { - text: string; - onClick: () => void; - isDisabled?: boolean; -} diff --git a/src/components/RecentActivity/RecentActivityTable/index.tsx b/src/components/RecentActivity/RecentActivityTable/index.tsx index abb9118ed..8c9437ae0 100644 --- a/src/components/RecentActivity/RecentActivityTable/index.tsx +++ b/src/components/RecentActivity/RecentActivityTable/index.tsx @@ -18,7 +18,6 @@ import { SnailIcon } from "../../common/icons/SnailIcon"; import { SpotIcon } from "../../common/icons/SpotIcon"; import { ViewMode } from "../EnvironmentPanel/types"; import { ActivityEntry, EntrySpan, SlimInsight } from "../types"; -import { SpanLink } from "./SpanLink"; import * as s from "./styles"; import { INSIGHT_TYPES, RecentActivityTableProps } from "./types"; @@ -99,13 +98,14 @@ export const RecentActivityTable = (props: RecentActivityTableProps) => { }; const renderSpanLink = (span: EntrySpan, environment: string) => ( - { handleSpanLinkClick(span, environment); }} - text={span.displayText} - /> + > + {span.displayText} + ); const renderSpanLinks = (entry: ActivityEntry) => ( @@ -164,7 +164,9 @@ export const RecentActivityTable = (props: RecentActivityTableProps) => { onClick={() => { handleTraceButtonClick(entry.latestTraceId, entry.firstEntrySpan); }} - icon={CrosshairIcon} + icon={{ + component: CrosshairIcon + }} > Trace diff --git a/src/components/RecentActivity/RecentActivityTable/styles.ts b/src/components/RecentActivity/RecentActivityTable/styles.ts index bea6373d8..a2d6e7c9a 100644 --- a/src/components/RecentActivity/RecentActivityTable/styles.ts +++ b/src/components/RecentActivity/RecentActivityTable/styles.ts @@ -1,4 +1,6 @@ import styled from "styled-components"; +import { getCodeFont } from "../../common/App/styles"; +import { Link } from "../../common/Link"; export const Table = styled.table` width: 100%; @@ -204,3 +206,19 @@ export const ListBadgeContainer = styled.div` export const ListSuffix = styled(Suffix)` font-size: 12px; `; + +export const SpanLink = styled(Link)` + ${({ theme }) => getCodeFont(theme.codeFont)} + font-size: 12px; + line-height: 14px; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#426dda"; + case "dark": + case "dark-jetbrains": + return "#7891d0"; + } + }}; +`; diff --git a/src/components/RecentActivity/styles.ts b/src/components/RecentActivity/styles.ts index 7f284b213..d1c11348f 100644 --- a/src/components/RecentActivity/styles.ts +++ b/src/components/RecentActivity/styles.ts @@ -1,4 +1,5 @@ import styled from "styled-components"; +import { Link } from "../common/Link"; export const Container = styled.div` min-height: 100vh; @@ -84,10 +85,11 @@ export const NoDataText = styled.span` margin-top: 4px; `; -export const DocumentationLink = styled.a` - font-weight: 400; +export const DocumentationLink = styled(Link)` font-size: 10px; line-height: 16px; + text-decoration: none; + color: ${({ theme }) => { switch (theme.mode) { case "light": @@ -97,5 +99,4 @@ export const DocumentationLink = styled.a` return "#7891d0"; } }}; - text-decoration: none; `; diff --git a/src/components/common/App/styles.ts b/src/components/common/App/styles.ts index d1b858f8d..24cf63a8a 100644 --- a/src/components/common/App/styles.ts +++ b/src/components/common/App/styles.ts @@ -1,6 +1,7 @@ import { createGlobalStyle, css, + DefaultTheme, FlattenSimpleInterpolation } from "styled-components"; import { environment } from "../../../environment"; @@ -69,17 +70,19 @@ export const getCodeFont = (customFont: string): FlattenSimpleInterpolation => { `; }; +export const getThemeKind = (theme: DefaultTheme): "light" | "dark" => { + switch (theme.mode) { + case "light": + return "light"; + case "dark": + case "dark-jetbrains": + return "dark"; + } +}; + export const GlobalStyle = createGlobalStyle` :root { - color-scheme: ${({ theme }) => { - switch (theme.mode) { - case "light": - return "light"; - case "dark": - case "dark-jetbrains": - return "dark"; - } - }}; + color-scheme: ${({ theme }) => getThemeKind(theme)}; } html, body, #root { diff --git a/src/components/common/AssetEntry/styles.ts b/src/components/common/AssetEntry/styles.ts index d9c63aa8b..2ac2b6fa6 100644 --- a/src/components/common/AssetEntry/styles.ts +++ b/src/components/common/AssetEntry/styles.ts @@ -28,7 +28,6 @@ export const OpenTelemetryIconContainer = styled.div` export const Link = styled.a` color: #7891d0; text-decoration: none; - font-style: normal; font-weight: 500; font-size: 12px; line-height: 14px; diff --git a/src/components/common/Button/index.tsx b/src/components/common/Button/index.tsx index de4d638b1..5fb2bc50c 100644 --- a/src/components/common/Button/index.tsx +++ b/src/components/common/Button/index.tsx @@ -1,20 +1,84 @@ -import React, { useCallback, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { DefaultTheme, useTheme } from "styled-components"; import * as s from "./styles"; -import { ButtonProps } from "./types"; +import { ButtonProps, ButtonType } from "./types"; const getIconColor = ( theme: DefaultTheme, isDisabled: boolean, isHovered: boolean, - isFocused: boolean + isFocused: boolean, + isPressed: boolean, + buttonType: ButtonType ): string => { + if (buttonType === "secondary") { + if (isDisabled) { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + } + + if (isPressed) { + switch (theme.mode) { + case "light": + return "#3538cd"; + case "dark": + case "dark-jetbrains": + return "#e2e7ff"; + } + } + + if (isHovered || isFocused) { + switch (theme.mode) { + case "light": + return "#5154ec"; + case "dark": + case "dark-jetbrains": + return "#e2e7ff"; + } + } + + switch (theme.mode) { + case "light": + return "#3538cd"; + case "dark": + case "dark-jetbrains": + return "#b9c2eb"; + } + } + if (isDisabled) { - return theme.mode === "light" ? "#f1f5fa" : "#7c7c94"; + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + } + + if (isPressed) { + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#dadada"; + } } if (isFocused || isHovered) { - return "#dadada"; + switch (theme.mode) { + case "light": + return "#e2e7ff"; + case "dark": + case "dark-jetbrains": + return "#b9c2eb"; + } } return "#b9c2eb"; @@ -25,6 +89,7 @@ export const Button = (props: ButtonProps) => { const [isHovered, setIsHovered] = useState(false); const [isFocused, setIsFocused] = useState(false); + const [isPressed, setIsPressed] = useState(false); const handleMouseEnter = useCallback(() => setIsHovered(true), []); const handleMouseLeave = useCallback(() => setIsHovered(false), []); @@ -32,10 +97,28 @@ export const Button = (props: ButtonProps) => { const handleFocus = useCallback(() => setIsFocused(true), []); const handleBlur = useCallback(() => setIsFocused(false), []); + const handleMouseDown = useCallback(() => setIsPressed(true), []); + + useEffect(() => { + const handleMouseUp = () => { + setIsPressed(false); + }; + + window.addEventListener("mouseup", handleMouseUp); + + return () => { + window.removeEventListener("mouseup", handleMouseUp); + }; + }, []); + const handleClick = (e: React.MouseEvent) => { - props.onClick(e); + if (props.onClick) { + props.onClick(e); + } }; + const buttonType = props.buttonType || "primary"; + return ( { onMouseLeave={handleMouseLeave} onFocus={handleFocus} onBlur={handleBlur} + onMouseDown={handleMouseDown} + buttonType={buttonType} > {props.icon && ( - )} {props.children} diff --git a/src/components/common/Button/styles.ts b/src/components/common/Button/styles.ts index 505416a7f..76d011a91 100644 --- a/src/components/common/Button/styles.ts +++ b/src/components/common/Button/styles.ts @@ -1,51 +1,212 @@ import styled from "styled-components"; +import { ButtonElementProps } from "./types"; -export const Button = styled.button` +export const Button = styled.button` font-family: inherit; font-weight: 500; font-size: 10px; + line-height: 12px; padding: 2px 4px; - height: 16px; border-radius: 2px; - border: none; - color: #b9c2eb; - background: #3538cd; cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + width: max-content; + user-select: none; - &:hover { - color: #dadada; - background: #5154ec; - } + color: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "#3538cd"; + case "dark": + case "dark-jetbrains": + return "#b9c2eb"; + } + } + + return "#b9c2eb"; + }}; + + background: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "none"; + case "dark": + case "dark-jetbrains": + return "#414363"; + } + } + + return "#3538cd"; + }}; + + border: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "1px solid #3538cd"; + case "dark": + case "dark-jetbrains": + return "1px solid #5154ec"; + } + } + return "none"; + }}; + + &:hover, &:focus { - color: #dadada; - background: #3538cd; + color: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "#5154ec"; + case "dark": + case "dark-jetbrains": + return "#e2e7ff"; + } + } + + switch (theme.mode) { + case "light": + return "#e2e7ff"; + case "dark": + case "dark-jetbrains": + return "#b9c2eb"; + } + }}; + + background: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "#eeeefd"; + case "dark": + case "dark-jetbrains": + return "#414363"; + } + } + + return "#5154ec"; + }}; + + border: ${({ buttonType }) => { + if (buttonType === "secondary") { + return "1px solid #5154ec"; + } + + return "none"; + }}; + } + + &:active { + color: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "#3538cd"; + case "dark": + case "dark-jetbrains": + return "#e2e7ff"; + } + } + + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#dadada"; + } + }}; + + background: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "#eeeefd"; + case "dark": + case "dark-jetbrains": + return "#414363"; + } + } + + return "#3538cd"; + }}; + + border: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "1px solid #3538cd"; + case "dark": + case "dark-jetbrains": + return "1px solid #5154ec"; + } + } + + return "none"; + }}; } &:disabled { - color: ${({ theme }) => { + cursor: initial; + + color: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + } + switch (theme.mode) { case "light": return "#f1f5fa"; case "dark": case "dark-jetbrains": - return "#7c7c94"; + return "#49494d"; } }}; - background: ${({ theme }) => { + + background: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + return "none"; + } + switch (theme.mode) { case "light": return "#b9c0d4"; case "dark": case "dark-jetbrains": - return "#49494d"; + return "#2e2e2e"; } }}; - cursor: initial; + + border: ${({ theme, buttonType }) => { + if (buttonType === "secondary") { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + } + + return "none"; + }}; } `; export const ContentContainer = styled.span` display: flex; gap: 2px; + align-items: center; `; diff --git a/src/components/common/Button/types.ts b/src/components/common/Button/types.ts index 8510bb915..6a6983a35 100644 --- a/src/components/common/Button/types.ts +++ b/src/components/common/Button/types.ts @@ -1,10 +1,21 @@ -import { ComponentType } from "react"; +import { ComponentType, MouseEventHandler, ReactNode } from "react"; import { IconProps } from "../icons/types"; +export type ButtonType = "primary" | "secondary"; + export interface ButtonProps { - icon?: ComponentType; - children: React.ReactNode; - onClick: React.MouseEventHandler; + icon?: { + component: ComponentType; + color?: string; + size?: number; + }; + children: ReactNode; + onClick?: MouseEventHandler; disabled?: boolean; className?: string; + buttonType?: ButtonType; +} + +export interface ButtonElementProps { + buttonType?: ButtonType; } diff --git a/src/components/common/FloatingIconButton/index.tsx b/src/components/common/FloatingIconButton/index.tsx new file mode 100644 index 000000000..ef9232719 --- /dev/null +++ b/src/components/common/FloatingIconButton/index.tsx @@ -0,0 +1,93 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { DefaultTheme, useTheme } from "styled-components"; +import * as s from "./styles"; +import { FloatingIconButtonProps } from "./types"; + +const getIconColor = ( + theme: DefaultTheme, + isDisabled: boolean, + isHovered: boolean, + isFocused: boolean, + isPressed: boolean +): string => { + if (isDisabled) { + return "#49494d"; + } + + if (isPressed) { + return "#b9c2eb"; + } + + if (isFocused || isHovered) { + return "#7891d0"; + } + + switch (theme.mode) { + case "light": + return "#7891D0"; + case "dark": + case "dark-jetbrains": + return "#b9c2eb"; + } +}; + +export const FloatingIconButton = (props: FloatingIconButtonProps) => { + const theme = useTheme(); + + const [isHovered, setIsHovered] = useState(false); + const [isFocused, setIsFocused] = useState(false); + const [isPressed, setIsPressed] = useState(false); + + const handleMouseEnter = useCallback(() => setIsHovered(true), []); + const handleMouseLeave = useCallback(() => setIsHovered(false), []); + + const handleFocus = useCallback(() => setIsFocused(true), []); + const handleBlur = useCallback(() => setIsFocused(false), []); + + const handleMouseDown = useCallback(() => setIsPressed(true), []); + + useEffect(() => { + const handleMouseUp = () => { + setIsPressed(false); + }; + + window.addEventListener("mouseup", handleMouseUp); + + return () => { + window.removeEventListener("mouseup", handleMouseUp); + }; + }, []); + + const handleClick = (e: React.MouseEvent) => { + if (props.onClick) { + props.onClick(e); + } + }; + + return ( + + + + ); +}; diff --git a/src/components/common/FloatingIconButton/styles.ts b/src/components/common/FloatingIconButton/styles.ts new file mode 100644 index 000000000..ff22fe6b8 --- /dev/null +++ b/src/components/common/FloatingIconButton/styles.ts @@ -0,0 +1,104 @@ +import styled from "styled-components"; + +export const Button = styled.button` + padding: 6px; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + width: max-content; + user-select: none; + + box-shadow: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "1px 1px 3px rgba(0, 0, 0, 0.15)"; + case "dark": + case "dark-jetbrains": + return "1px 1px 4px rgba(0, 0, 0, 0.25)"; + } + }}; + + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#2e2e2e"; + } + }}; + + border: 1px solid + ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#fbfdff"; + case "dark": + case "dark-jetbrains": + return "#383838"; + } + }}; + + &:hover, + &:focus { + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + }}; + } + + &:active { + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#2e2e2e"; + } + }}; + + border: 1px solid + ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#fbfdff"; + case "dark": + case "dark-jetbrains": + return "#383838"; + } + }}; + } + + &:disabled { + cursor: initial; + + background: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return "#2e2e2e"; + } + }}; + + border: 1px solid + ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#fbfdff"; + case "dark": + case "dark-jetbrains": + return "#383838"; + } + }}; + } +`; diff --git a/src/components/common/FloatingIconButton/types.ts b/src/components/common/FloatingIconButton/types.ts new file mode 100644 index 000000000..3c318a52a --- /dev/null +++ b/src/components/common/FloatingIconButton/types.ts @@ -0,0 +1,13 @@ +import { ComponentType, MouseEventHandler } from "react"; +import { IconProps } from "../icons/types"; + +export interface FloatingIconButtonProps { + icon: { + component: ComponentType; + color?: string; + size?: number; + }; + onClick?: MouseEventHandler; + disabled?: boolean; + className?: string; +} diff --git a/src/components/common/Link/index.tsx b/src/components/common/Link/index.tsx new file mode 100644 index 000000000..afe3ee8be --- /dev/null +++ b/src/components/common/Link/index.tsx @@ -0,0 +1,30 @@ +import { ForwardedRef, MouseEvent, forwardRef } from "react"; +import * as s from "./styles"; +import { LinkProps } from "./types"; + +const LinkComponent = ( + props: LinkProps, + ref: ForwardedRef +) => { + const handleClick = (e: MouseEvent) => { + if (props.onClick) { + e.preventDefault(); + props.onClick(); + } + }; + + return ( + + {props.children} + + ); +}; + +export const Link = forwardRef(LinkComponent); diff --git a/src/components/common/Link/styles.ts b/src/components/common/Link/styles.ts new file mode 100644 index 000000000..4748b7aa4 --- /dev/null +++ b/src/components/common/Link/styles.ts @@ -0,0 +1,54 @@ +import styled from "styled-components"; + +export const Link = styled.a` + font-size: 8px; + line-height: 10px; + cursor: pointer; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#426dda"; + case "dark": + case "dark-jetbrains": + return "#b9c2eb"; + } + }}; + + &:hover, + &:focus { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#002d61"; + case "dark": + case "dark-jetbrains": + return "#e2e7ff"; + } + }}; + } + + &:active { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#002d61"; + case "dark": + case "dark-jetbrains": + return "#7891d0"; + } + }}; + } + + &:disabled { + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return "#49494d"; + } + }}; + } +`; diff --git a/src/components/common/Link/types.ts b/src/components/common/Link/types.ts new file mode 100644 index 000000000..87e15eb5d --- /dev/null +++ b/src/components/common/Link/types.ts @@ -0,0 +1,11 @@ +import { ReactNode } from "react"; + +export interface LinkProps { + href?: string; + target?: string; + rel?: string; + onClick?: () => void; + disabled?: boolean; + children: ReactNode; + className?: string; +} diff --git a/src/components/common/Loader/index.tsx b/src/components/common/Loader/index.tsx index 702deed9a..3afef7393 100644 --- a/src/components/common/Loader/index.tsx +++ b/src/components/common/Loader/index.tsx @@ -44,19 +44,19 @@ const LoaderComponent = (props: LoaderProps) => { viewBox="0 0 143 143" > { d="M90.5996 112.82C90.539 114.751 90.3434 116.675 90.0142 118.578C91.7225 118.195 94.7456 116.371 95.5902 114.116C94.0217 113.377 92.3292 112.938 90.5996 112.82Z" /> { d="M28.505 86.1109C28.505 85.631 28.505 85.1512 28.5722 84.6905C28.8084 81.6428 29.7166 78.6852 31.2316 76.0302C32.7466 73.3752 34.8308 71.0886 37.3345 69.3348C40.7566 66.9151 44.8425 65.6112 49.0336 65.6014C54.4969 65.6218 59.7284 67.8109 63.578 71.6875C67.4276 75.5641 69.5801 80.8108 69.5623 86.274V86.3412C69.5624 91.7813 67.4112 97.0006 63.5781 100.861C59.7449 104.721 54.5407 106.909 49.1008 106.947H49.0336C43.5754 106.929 38.3472 104.746 34.4966 100.878C30.6461 97.009 28.4877 91.7707 28.4954 86.3124C28.4954 86.2165 28.505 86.1685 28.505 86.1109Z" /> { d="M53.3236 89.4604L67.4412 84.1915L62.6809 75.7938L40.7991 90.3529L60.4831 83.0782L53.3236 89.4604Z" /> { d="M114.305 86.1146C114.305 85.6347 114.305 85.1549 114.238 84.6942C114.002 81.6465 113.093 78.6889 111.578 76.0339C110.063 73.3789 107.979 71.0924 105.475 69.3385C102.052 66.9326 97.9699 65.6422 93.7859 65.6436C91.08 65.6524 88.4022 66.1941 85.9057 67.2377C83.4091 68.2814 81.1425 69.8066 79.2353 71.7262C77.3282 73.6458 75.8178 75.9223 74.7904 78.4257C73.7631 80.929 73.2388 83.6102 73.2477 86.3162V86.3833C73.2475 91.8234 75.3987 97.0427 79.2319 100.903C83.0651 104.763 88.2692 106.951 93.7091 106.989H93.7859C99.2433 106.971 104.47 104.788 108.32 100.919C112.169 97.0502 114.325 91.8119 114.315 86.3545C114.315 86.2202 114.305 86.1722 114.305 86.1146Z" /> { d="M97.7881 88.2572L111.906 82.9883L107.145 74.5811L85.2732 89.1498L104.948 81.8654L97.7881 88.2572Z" /> { viewBox="0 0 143 143" > { d="M90.5996 112.82C90.539 114.751 90.3434 116.675 90.0142 118.578C91.7225 118.195 94.7456 116.371 95.5902 114.116C94.0217 113.377 92.3292 112.938 90.5996 112.82Z" /> { d="M28.505 86.1109C28.505 85.631 28.505 85.1512 28.5722 84.6905C28.8084 81.6428 29.7166 78.6852 31.2317 76.0302C32.7467 73.3752 34.8309 71.0886 37.3346 69.3348C40.7567 66.9151 44.8425 65.6112 49.0337 65.6014C54.4969 65.6218 59.7285 67.8109 63.5781 71.6875C67.4277 75.5641 69.5802 80.8108 69.5623 86.274V86.3412C69.5624 91.7813 67.4113 97.0006 63.5781 100.861C59.7449 104.721 54.5408 106.909 49.1009 106.947H49.0337C43.5754 106.929 38.3473 104.746 34.4967 100.878C30.6461 97.009 28.4878 91.7707 28.4954 86.3124C28.4954 86.2165 28.505 86.1685 28.505 86.1109Z" /> { d="M53.3236 89.4604L67.4413 84.1914L62.681 75.7938L40.7992 90.3529L60.4832 83.0781L53.3236 89.4604Z" /> { d="M114.305 86.1145C114.305 85.6347 114.305 85.1548 114.238 84.6941C114.002 81.6464 113.093 78.6888 111.578 76.0338C110.063 73.3788 107.979 71.0923 105.475 69.3385C102.052 66.9326 97.97 65.6421 93.786 65.6435C91.08 65.6523 88.4023 66.194 85.9057 67.2377C83.4091 68.2813 81.1425 69.8065 79.2354 71.7262C77.3282 73.6458 75.8179 75.9223 74.7905 78.4256C73.7631 80.929 73.2389 83.6101 73.2477 86.3161V86.3833C73.2476 91.8233 75.3988 97.0427 79.2319 100.903C83.0651 104.763 88.2693 106.951 93.7092 106.989H93.786C99.2433 106.971 104.471 104.788 108.32 100.919C112.169 97.0502 114.325 91.8119 114.315 86.3545C114.315 86.2201 114.305 86.1721 114.305 86.1145Z" /> { d="M97.7881 88.2572L111.906 82.9882L107.146 74.581L85.2733 89.1497L104.948 81.8653L97.7881 88.2572Z" /> { clipRule="evenodd" /> @@ -278,7 +278,7 @@ const LoaderComponent = (props: LoaderProps) => { clipRule="evenodd" /> @@ -294,19 +294,19 @@ const LoaderComponent = (props: LoaderProps) => { viewBox="0 0 143 143" > { d="M90.5996 112.82C90.539 114.751 90.3434 116.675 90.0142 118.578C91.7225 118.195 94.7456 116.371 95.5902 114.116C94.0217 113.377 92.3292 112.938 90.5996 112.82Z" /> { d="M53.3236 89.4604L67.4412 84.1915L62.6809 75.7938L40.7991 90.3529L60.4831 83.0782L53.3236 89.4604Z" /> { d="M97.7881 88.2572L111.906 82.9883L107.145 74.5811L85.2732 89.1498L104.948 81.8654L97.7881 88.2572Z" /> diff --git a/src/components/common/Loader/types.ts b/src/components/common/Loader/types.ts index 314c6d004..3dff94137 100644 --- a/src/components/common/Loader/types.ts +++ b/src/components/common/Loader/types.ts @@ -1,4 +1,5 @@ export interface LoaderProps { size?: number; + themeKind?: "light" | "dark"; status: "pending" | "success" | "failure"; } diff --git a/src/components/common/ToggleSwitch/styles.ts b/src/components/common/ToggleSwitch/styles.ts index e237b16f3..3683a8cbc 100644 --- a/src/components/common/ToggleSwitch/styles.ts +++ b/src/components/common/ToggleSwitch/styles.ts @@ -3,7 +3,6 @@ import { CircleProps, SwitchContainerProps } from "./types"; export const Container = styled.div` display: flex; - color: #fff; font-size: 10px; font-weight: 500; line-height: 12px; @@ -12,26 +11,53 @@ export const Container = styled.div` align-items: center; cursor: pointer; user-select: none; + + color: ${({ theme }) => { + switch (theme.mode) { + case "light": + return "#788ca9"; + case "dark": + case "dark-jetbrains": + return "#fff"; + } + }}; `; export const SwitchContainer = styled.div` border-radius: 8px; - background: ${({ isChecked }) => (isChecked ? "#3538cd" : "#7c7c94")}; width: 28px; height: 16px; - position: relative; transition-property: background; transition-duration: 0.3s; + display: flex; + align-items: center; + + background: ${({ isChecked, theme }) => { + switch (theme.mode) { + case "light": + return isChecked ? "#3538cd" : "#b9c0d4"; + case "dark": + case "dark-jetbrains": + return isChecked ? "#3538cd" : "#7c7c94"; + } + }}; `; export const Circle = styled.div` width: 8px; height: 8px; border-radius: 50%; - background: ${({ isChecked }) => (isChecked ? "#fbfdff" : "#b9c0d4")}; - position: absolute; - top: 4px; - left: ${({ isChecked }) => (isChecked ? "16px" : "4px")}; - transition-property: background, left; + transition-property: background, margin-left; transition-duration: 0.3s; + + margin-left: ${({ isChecked }) => (isChecked ? "16px" : "4px")}; + background: ${({ isChecked, theme }) => { + switch (theme.mode) { + case "light": + return isChecked ? "#fbfdff" : "#f1f5fa"; + case "dark": + case "dark-jetbrains": + return isChecked ? "#fbfdff" : "#b9c0d4"; + } + }}; `; diff --git a/src/components/common/icons/CheckmarkCircleInvertedIcon.tsx b/src/components/common/icons/CheckmarkCircleInvertedIcon.tsx index c2ade8b22..197613b7e 100644 --- a/src/components/common/icons/CheckmarkCircleInvertedIcon.tsx +++ b/src/components/common/icons/CheckmarkCircleInvertedIcon.tsx @@ -11,20 +11,15 @@ const CheckmarkCircleInvertedIconComponent = (props: IconProps) => { width={size} height={size} fill="none" - viewBox="0 0 12 12" + viewBox="0 0 16 16" > - + ); }; diff --git a/src/components/common/icons/DigmaLogoFlatIcon.tsx b/src/components/common/icons/DigmaLogoFlatIcon.tsx index fe36aeef8..3d6ed386c 100644 --- a/src/components/common/icons/DigmaLogoFlatIcon.tsx +++ b/src/components/common/icons/DigmaLogoFlatIcon.tsx @@ -3,7 +3,7 @@ import { useIconProps } from "./hooks"; import { IconProps } from "./types"; const DigmaLogoFlatIconComponent = (props: IconProps) => { - const { size, color } = useIconProps(props); + const { size } = useIconProps(props); return (