From f843f23cb7023ffa872de0d8511124078cbd3761 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 12 Sep 2024 21:28:08 +0000 Subject: [PATCH 01/43] chore: finish draft work for FeatureBadge component --- .../FeatureBadge/FeatureBadge.stories.tsx | 22 ++++++ .../components/FeatureBadge/FeatureBadge.tsx | 67 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 site/src/components/FeatureBadge/FeatureBadge.stories.tsx create mode 100644 site/src/components/FeatureBadge/FeatureBadge.tsx diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx new file mode 100644 index 0000000000000..32072c3facaad --- /dev/null +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -0,0 +1,22 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { FeatureBadge } from "./FeatureBadge"; + +const meta: Meta = { + title: "components/FeatureBadge", + component: FeatureBadge, +}; + +export default meta; +type Story = StoryObj; + +export const Small: Story = { + args: { + size: "sm", + }, +}; + +export const Medium: Story = { + args: { + size: "md", + }, +}; diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx new file mode 100644 index 0000000000000..73ef11d7f2fa3 --- /dev/null +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -0,0 +1,67 @@ +import type { Interpolation, Theme } from "@emotion/react"; +import type { FC, HTMLAttributes, ReactNode } from "react"; + +/** + * All types of feature that we are currently supporting. Defined as record to + * ensure that we can't accidentally make typos when writing the badge text. + */ +const featureBadgeTypes = { + beta: "beta", + earlyAccess: "early access", +} as const satisfies Record; + +const styles = { + badge: (theme) => ({ + // Base type is based on a span so that the element can be placed inside + // more types of HTML elements without creating invalid markdown, but we + // still want the default display behavior to be div-like + display: "block", + maxWidth: "fit-content", + flexShrink: 0, + padding: "8px 4px", + border: `1px solid ${theme.palette.divider}`, + color: theme.palette.text.secondary, + backgroundColor: theme.palette.background.default, + borderRadius: "6px", + + // Base style assumes that small badges will be the default + fontSize: "0.75rem", + }), + + highlighted: (theme) => ({ + color: theme.palette.text.primary, + borderColor: theme.palette.text.primary, + }), + + mediumText: { + fontSize: "1rem", + }, +} as const satisfies Record>; + +type FeatureBadgeProps = Readonly< + Omit, "children"> & { + type: keyof typeof featureBadgeTypes; + size?: "sm" | "md"; + isHighlighted?: boolean; + } +>; + +export const FeatureBadge: FC = ({ + type, + size = "sm", + isHighlighted = false, + ...delegatedProps +}) => { + return ( + + {featureBadgeTypes[type]} + + ); +}; From 43874a4a239aa8282d255a10f42e0d817f88de28 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 12 Sep 2024 21:36:42 +0000 Subject: [PATCH 02/43] fix: add visually-hidden helper text for screen readers --- site/src/components/FeatureBadge/FeatureBadge.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 73ef11d7f2fa3..7c10a404858a4 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -1,4 +1,5 @@ import type { Interpolation, Theme } from "@emotion/react"; +import { visuallyHidden } from "@mui/utils"; import type { FC, HTMLAttributes, ReactNode } from "react"; /** @@ -61,7 +62,9 @@ export const FeatureBadge: FC = ({ ]} {...delegatedProps} > + (This feature is {featureBadgeTypes[type]} + ) ); }; From fb70781f771ed2f6190674ddb55883fb283fc691 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 12 Sep 2024 21:39:55 +0000 Subject: [PATCH 03/43] chore: add stories for highlighted state --- .../FeatureBadge/FeatureBadge.stories.tsx | 14 ++++++++++++++ site/src/components/FeatureBadge/FeatureBadge.tsx | 6 +++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 32072c3facaad..3db8210787d2a 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -20,3 +20,17 @@ export const Medium: Story = { size: "md", }, }; + +export const HighlightedSmall: Story = { + args: { + size: "sm", + highlighted: true, + }, +}; + +export const HighlightedMedium: Story = { + args: { + size: "md", + highlighted: true, + }, +}; diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 7c10a404858a4..dd63ea48a4a43 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -43,14 +43,14 @@ type FeatureBadgeProps = Readonly< Omit, "children"> & { type: keyof typeof featureBadgeTypes; size?: "sm" | "md"; - isHighlighted?: boolean; + highlighted?: boolean; } >; export const FeatureBadge: FC = ({ type, size = "sm", - isHighlighted = false, + highlighted = false, ...delegatedProps }) => { return ( @@ -58,7 +58,7 @@ export const FeatureBadge: FC = ({ css={[ styles.badge, size === "md" && styles.mediumText, - isHighlighted && styles.highlighted, + highlighted && styles.highlighted, ]} {...delegatedProps} > From c2470f97f5868964494e4667c785f2a1d3f2ac14 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 12 Sep 2024 21:50:49 +0000 Subject: [PATCH 04/43] fix: update base styles --- .../components/FeatureBadge/FeatureBadge.stories.tsx | 3 +++ site/src/components/FeatureBadge/FeatureBadge.tsx | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 3db8210787d2a..8b5236eb774a1 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -4,6 +4,9 @@ import { FeatureBadge } from "./FeatureBadge"; const meta: Meta = { title: "components/FeatureBadge", component: FeatureBadge, + args: { + type: "beta", + }, }; export default meta; diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index dd63ea48a4a43..0163292133a67 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -17,16 +17,19 @@ const styles = { // more types of HTML elements without creating invalid markdown, but we // still want the default display behavior to be div-like display: "block", + + // Base style assumes that small badges will be the default + fontSize: "0.75rem", + maxWidth: "fit-content", flexShrink: 0, - padding: "8px 4px", + padding: "4px 8px", + lineHeight: 1, + whiteSpace: "nowrap", border: `1px solid ${theme.palette.divider}`, color: theme.palette.text.secondary, backgroundColor: theme.palette.background.default, borderRadius: "6px", - - // Base style assumes that small badges will be the default - fontSize: "0.75rem", }), highlighted: (theme) => ({ From 693946f78df903c8e6b815e5500be766dcc4e87e Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 12 Sep 2024 21:54:48 +0000 Subject: [PATCH 05/43] chore: remove debug display option --- site/src/components/FeatureBadge/FeatureBadge.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 0163292133a67..0872a4b82faa4 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -8,7 +8,6 @@ import type { FC, HTMLAttributes, ReactNode } from "react"; */ const featureBadgeTypes = { beta: "beta", - earlyAccess: "early access", } as const satisfies Record; const styles = { From 129613b743b206eeeac2bbf4ffc630dd891402cf Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 13 Sep 2024 19:46:43 +0000 Subject: [PATCH 06/43] chore: update Popover to propagate events --- site/src/components/Popover/Popover.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/site/src/components/Popover/Popover.tsx b/site/src/components/Popover/Popover.tsx index 7db3c4eda1799..43db214b0f097 100644 --- a/site/src/components/Popover/Popover.tsx +++ b/site/src/components/Popover/Popover.tsx @@ -1,10 +1,10 @@ import MuiPopover, { type PopoverProps as MuiPopoverProps, - // biome-ignore lint/nursery/noRestrictedImports: Used as base component } from "@mui/material/Popover"; import { type FC, type HTMLAttributes, + type PointerEvent, type ReactElement, type ReactNode, type RefObject, @@ -95,17 +95,20 @@ export const PopoverTrigger = ( const { children, ...elementProps } = props; const clickProps = { - onClick: () => { + onClick: (event: PointerEvent) => { popover.setOpen(true); + elementProps.onClick?.(event); }, }; const hoverProps = { - onPointerEnter: () => { + onPointerEnter: (event: PointerEvent) => { popover.setOpen(true); + elementProps.onPointerEnter?.(event); }, - onPointerLeave: () => { + onPointerLeave: (event: PointerEvent) => { popover.setOpen(false); + elementProps.onPointerLeave?.(event); }, }; From 6adea6b60652a7691c749b2df0b3d970089ecefe Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 13 Sep 2024 19:47:04 +0000 Subject: [PATCH 07/43] wip: commit progress on FeatureBadge update --- .../FeatureBadge/FeatureBadge.stories.tsx | 23 +-- .../components/FeatureBadge/FeatureBadge.tsx | 134 ++++++++++++++++-- 2 files changed, 123 insertions(+), 34 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 8b5236eb774a1..1d522ed83748c 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -12,28 +12,9 @@ const meta: Meta = { export default meta; type Story = StoryObj; -export const Small: Story = { +export const SmallInteractive: Story = { args: { size: "sm", - }, -}; - -export const Medium: Story = { - args: { - size: "md", - }, -}; - -export const HighlightedSmall: Story = { - args: { - size: "sm", - highlighted: true, - }, -}; - -export const HighlightedMedium: Story = { - args: { - size: "md", - highlighted: true, + variant: "interactive", }, }; diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 0872a4b82faa4..ff1105cc8426f 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -1,6 +1,16 @@ import type { Interpolation, Theme } from "@emotion/react"; +import Link from "@mui/material/Link"; import { visuallyHidden } from "@mui/utils"; -import type { FC, HTMLAttributes, ReactNode } from "react"; +import { HelpTooltipContent } from "components/HelpTooltip/HelpTooltip"; +import { Popover, PopoverTrigger } from "components/Popover/Popover"; +import { + useEffect, + useState, + type FC, + type HTMLAttributes, + type ReactNode, +} from "react"; +import { docs } from "utils/docs"; /** * All types of feature that we are currently supporting. Defined as record to @@ -8,6 +18,7 @@ import type { FC, HTMLAttributes, ReactNode } from "react"; */ const featureBadgeTypes = { beta: "beta", + experimental: "experimental", } as const satisfies Record; const styles = { @@ -16,11 +27,12 @@ const styles = { // more types of HTML elements without creating invalid markdown, but we // still want the default display behavior to be div-like display: "block", + maxWidth: "fit-content", // Base style assumes that small badges will be the default fontSize: "0.75rem", - maxWidth: "fit-content", + cursor: "default", flexShrink: 0, padding: "4px 8px", lineHeight: 1, @@ -31,42 +43,138 @@ const styles = { borderRadius: "6px", }), - highlighted: (theme) => ({ + badgeHover: (theme) => ({ color: theme.palette.text.primary, borderColor: theme.palette.text.primary, }), - mediumText: { + badgeLargeText: { fontSize: "1rem", }, + + tooltipTitle: { + fontWeight: 600, + fontFamily: "inherit", + fontSize: 18, + margin: 0, + lineHeight: 1, + paddingBottom: "8px", + }, + + tooltipDescription: { + margin: 0, + lineHeight: 1.2, + }, } as const satisfies Record>; type FeatureBadgeProps = Readonly< Omit, "children"> & { type: keyof typeof featureBadgeTypes; - size?: "sm" | "md"; - highlighted?: boolean; + size?: "sm" | "lg"; + + /** + * Defines how the FeatureBadge should render. + * - interactive (default) - The badge functions like a link and + * controls its own hover styling. + * - static - The badge is completely static and has no interaction + * behavior. + * - staticHover - The badge is completely static, but displays badge + hover styling (but nothing related to links). Useful if you want a + parent component to control the hover styling. + */ + variant?: "interactive" | "static" | "staticHover"; } >; export const FeatureBadge: FC = ({ type, size = "sm", - highlighted = false, + variant = "interactive", + onPointerEnter, + onPointerLeave, ...delegatedProps }) => { - return ( + const [isBadgeHovering, setIsBadgeHovering] = useState(false); + useEffect(() => { + const onWindowBlur = () => { + setIsBadgeHovering(false); + }; + + window.addEventListener("blur", onWindowBlur); + return () => window.removeEventListener("blur", onWindowBlur); + }, []); + + const featureType = featureBadgeTypes[type]; + const showHoverStyles = + variant === "staticHover" || (variant === "interactive" && isBadgeHovering); + + const coreContent = ( - (This feature is - {featureBadgeTypes[type]} - ) + (This is a + {featureType} + feature) ); + + if (variant !== "interactive") { + return coreContent; + } + + return ( + + { + setIsBadgeHovering(true); + onPointerEnter?.(event); + }} + onPointerLeave={(event) => { + setIsBadgeHovering(false); + onPointerLeave?.(event); + }} + > + {coreContent} + + + +
+ {capitalizeFirstLetter(featureType)} Feature +
+ +

+ This is {getGrammaticalArticle(featureType)} {featureType} feature. It + has not yet been marked for general availability. +

+ + + Feature stage documentation + (link opens in new tab) + +
+
+ ); }; + +function getGrammaticalArticle(nextWord: string): string { + const vowels = ["a", "e", "i", "o", "u"]; + const firstLetter = nextWord.slice(0, 1).toLowerCase(); + return vowels.includes(firstLetter) ? "an" : "a"; +} + +function capitalizeFirstLetter(text: string): string { + return text.slice(0, 1).toUpperCase() + text.slice(1); +} From d4455a89f91d88cb6017ab11a9fb962d7d1dd33d Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 13 Sep 2024 20:05:09 +0000 Subject: [PATCH 08/43] wip: commit more progress --- .../FeatureBadge/FeatureBadge.stories.tsx | 11 ++++++++++- site/src/components/FeatureBadge/FeatureBadge.tsx | 15 +++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 1d522ed83748c..a4610a160802d 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -12,8 +12,17 @@ const meta: Meta = { export default meta; type Story = StoryObj; -export const SmallInteractive: Story = { +export const SmallInteractiveBeta: Story = { args: { + type: "beta", + size: "sm", + variant: "interactive", + }, +}; + +export const SmallInteractiveExperimental: Story = { + args: { + type: "experimental", size: "sm", variant: "interactive", }, diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index ff1105cc8426f..3ec1267a764ff 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -52,17 +52,24 @@ const styles = { fontSize: "1rem", }, - tooltipTitle: { + tooltipTitle: (theme) => ({ + color: theme.palette.text.primary, fontWeight: 600, fontFamily: "inherit", fontSize: 18, margin: 0, lineHeight: 1, paddingBottom: "8px", - }, + }), tooltipDescription: { margin: 0, + lineHeight: 1.4, + paddingBottom: "8px", + }, + + tooltipLink: { + fontWeight: 600, lineHeight: 1.2, }, } as const satisfies Record>; @@ -159,9 +166,9 @@ export const FeatureBadge: FC = ({ href={docs("/contributing/feature-stages")} target="_blank" rel="noreferrer" - css={{ fontWeight: 600 }} + css={styles.tooltipLink} > - Feature stage documentation + Learn about feature stages (link opens in new tab) From 8ae71d389e2040435cab04c7d881ff61e51cbcac Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 13 Sep 2024 20:17:04 +0000 Subject: [PATCH 09/43] chore: update tag definitions to satify Biome --- .../AppearancePage/AppearanceForm.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx index a4e520c2b7137..6559e31723156 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx @@ -175,23 +175,23 @@ const ThemePreview: FC = ({
-
-
-
+
+
+
-
-
+
+
-
+
-
-
-
-
-
+
+
+
+
+
From 0ad68afb99fc5bcf2d1708637b7e1dd22fd30f8c Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 13 Sep 2024 21:00:40 +0000 Subject: [PATCH 10/43] chore: update all colors for preview role --- .../components/FeatureBadge/FeatureBadge.tsx | 14 +++++--- site/src/theme/dark/roles.ts | 36 +++++++++++++++---- site/src/theme/darkBlue/roles.ts | 36 +++++++++++++++---- site/src/theme/index.ts | 1 - site/src/theme/light/roles.ts | 36 +++++++++++++++---- site/src/theme/roles.ts | 2 +- 6 files changed, 97 insertions(+), 28 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 3ec1267a764ff..353a44b527962 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -10,6 +10,7 @@ import { type HTMLAttributes, type ReactNode, } from "react"; +import tailwindColors from "theme/tailwindColors"; import { docs } from "utils/docs"; /** @@ -37,15 +38,18 @@ const styles = { padding: "4px 8px", lineHeight: 1, whiteSpace: "nowrap", - border: `1px solid ${theme.palette.divider}`, - color: theme.palette.text.secondary, - backgroundColor: theme.palette.background.default, + border: `1px solid ${theme.roles.preview.outline}`, + color: theme.roles.preview.text, + backgroundColor: theme.roles.preview.background, borderRadius: "6px", + transition: + "color 0.4s ease-in-out, border-color 0.4s ease-in-out, background-color 0.4s ease-in-out", }), badgeHover: (theme) => ({ - color: theme.palette.text.primary, - borderColor: theme.palette.text.primary, + color: theme.roles.preview.hover.text, + borderColor: theme.roles.preview.hover.outline, + backgroundColor: theme.roles.preview.hover.background, }), badgeLargeText: { diff --git a/site/src/theme/dark/roles.ts b/site/src/theme/dark/roles.ts index 32a9ea4f12992..dfefd1d10909b 100644 --- a/site/src/theme/dark/roles.ts +++ b/site/src/theme/dark/roles.ts @@ -1,7 +1,7 @@ import type { Roles } from "../roles"; import colors from "../tailwindColors"; -export default { +const roles: Roles = { danger: { background: colors.orange[950], outline: colors.orange[500], @@ -143,13 +143,35 @@ export default { }, }, preview: { - background: colors.violet[950], - outline: colors.violet[500], - text: colors.violet[50], + background: colors.cyan[950], + outline: colors.cyan[600], + text: colors.cyan[400], fill: { - solid: colors.violet[400], - outline: colors.violet[400], + solid: colors.cyan[400], + outline: colors.cyan[400], text: colors.white, }, + hover: { + background: colors.zinc[950], + outline: colors.cyan[500], + text: colors.cyan[300], + fill: { + text: colors.white, + outline: colors.cyan[600], + solid: colors.cyan[600], + }, + }, + disabled: { + background: colors.zinc[950], + outline: colors.cyan[500], + text: colors.cyan[300], + fill: { + text: colors.white, + outline: colors.cyan[600], + solid: colors.cyan[600], + }, + }, }, -} satisfies Roles; +}; + +export default roles; diff --git a/site/src/theme/darkBlue/roles.ts b/site/src/theme/darkBlue/roles.ts index 744b7329249b9..a0f36daa810b9 100644 --- a/site/src/theme/darkBlue/roles.ts +++ b/site/src/theme/darkBlue/roles.ts @@ -1,7 +1,7 @@ import type { Roles } from "../roles"; import colors from "../tailwindColors"; -export default { +const roles: Roles = { danger: { background: colors.orange[950], outline: colors.orange[500], @@ -143,13 +143,35 @@ export default { }, }, preview: { - background: colors.violet[950], - outline: colors.violet[500], - text: colors.violet[50], + background: colors.cyan[950], + outline: colors.cyan[600], + text: colors.cyan[400], fill: { - solid: colors.violet[400], - outline: colors.violet[400], + solid: colors.cyan[400], + outline: colors.cyan[400], text: colors.white, }, + hover: { + background: colors.zinc[950], + outline: colors.cyan[500], + text: colors.cyan[300], + fill: { + text: colors.white, + outline: colors.cyan[600], + solid: colors.cyan[600], + }, + }, + disabled: { + background: colors.zinc[950], + outline: colors.cyan[500], + text: colors.cyan[300], + fill: { + text: colors.white, + outline: colors.cyan[600], + solid: colors.cyan[600], + }, + }, }, -} satisfies Roles; +}; + +export default roles; diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts index 8509ccb4135a6..7516fe1207929 100644 --- a/site/src/theme/index.ts +++ b/site/src/theme/index.ts @@ -1,4 +1,3 @@ -// biome-ignore lint/nursery/noRestrictedImports: We still use `Theme` as a basis for our actual theme, for now. import type { Theme as MuiTheme } from "@mui/material/styles"; import type * as monaco from "monaco-editor"; import type { Branding } from "./branding"; diff --git a/site/src/theme/light/roles.ts b/site/src/theme/light/roles.ts index fe3d1d9687bfa..905d45384f247 100644 --- a/site/src/theme/light/roles.ts +++ b/site/src/theme/light/roles.ts @@ -1,7 +1,7 @@ import type { Roles } from "../roles"; import colors from "../tailwindColors"; -export default { +const roles: Roles = { danger: { background: colors.orange[50], outline: colors.orange[400], @@ -143,13 +143,35 @@ export default { }, }, preview: { - background: colors.violet[50], - outline: colors.violet[500], - text: colors.violet[950], + background: colors.cyan[100], + outline: colors.cyan[500], + text: colors.cyan[950], fill: { - solid: colors.violet[600], - outline: colors.violet[600], + solid: colors.cyan[600], + outline: colors.cyan[600], text: colors.white, }, + hover: { + background: colors.cyan[50], + outline: colors.cyan[600], + text: colors.cyan[950], + fill: { + outline: colors.cyan[500], + solid: colors.cyan[500], + text: colors.white, + }, + }, + disabled: { + background: colors.cyan[50], + outline: colors.cyan[800], + text: colors.cyan[200], + fill: { + solid: colors.cyan[800], + outline: colors.cyan[800], + text: colors.white, + }, + }, }, -} satisfies Roles; +}; + +export default roles; diff --git a/site/src/theme/roles.ts b/site/src/theme/roles.ts index 13d54f8840d20..87620bd43ef8c 100644 --- a/site/src/theme/roles.ts +++ b/site/src/theme/roles.ts @@ -36,7 +36,7 @@ export interface Roles { /** This isn't quite ready for prime-time, but you're welcome to look around! * Preview features, experiments, unstable, etc. */ - preview: Role; + preview: InteractiveRole; } /** From 781a6099b81089b5dc1e3d3b6332d0177145db79 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 13 Sep 2024 21:45:02 +0000 Subject: [PATCH 11/43] fix: make sure badge shows as hovered while inside tooltip --- .../FeatureBadge/FeatureBadge.stories.tsx | 16 +++++++++++++++ .../components/FeatureBadge/FeatureBadge.tsx | 20 ++++++++++++++----- site/src/components/Popover/Popover.tsx | 17 ++++++++++++---- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index a4610a160802d..7326015b23dae 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -27,3 +27,19 @@ export const SmallInteractiveExperimental: Story = { variant: "interactive", }, }; + +export const LargeInteractiveBeta: Story = { + args: { + type: "beta", + size: "lg", + variant: "interactive", + }, +}; + +export const LargeStaticBeta: Story = { + args: { + type: "beta", + size: "lg", + variant: "static", + }, +}; diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 353a44b527962..57ba3e05b754e 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -43,7 +43,7 @@ const styles = { backgroundColor: theme.roles.preview.background, borderRadius: "6px", transition: - "color 0.4s ease-in-out, border-color 0.4s ease-in-out, background-color 0.4s ease-in-out", + "color 0.2s ease-in-out, border-color 0.2s ease-in-out, background-color 0.2s ease-in-out", }), badgeHover: (theme) => ({ @@ -105,10 +105,15 @@ export const FeatureBadge: FC = ({ onPointerLeave, ...delegatedProps }) => { + // Not a big fan of having two hover variables, but we need to make sure the + // badge maintains its hover styling while the mouse is inside the tooltip const [isBadgeHovering, setIsBadgeHovering] = useState(false); + const [isTooltipHovering, setIsTooltipHovering] = useState(false); + useEffect(() => { const onWindowBlur = () => { setIsBadgeHovering(false); + setIsTooltipHovering(false); }; window.addEventListener("blur", onWindowBlur); @@ -116,16 +121,19 @@ export const FeatureBadge: FC = ({ }, []); const featureType = featureBadgeTypes[type]; - const showHoverStyles = - variant === "staticHover" || (variant === "interactive" && isBadgeHovering); + const showBadgeHoverStyle = + variant === "staticHover" || + (variant === "interactive" && (isBadgeHovering || isTooltipHovering)); const coreContent = ( (This is a @@ -156,6 +164,8 @@ export const FeatureBadge: FC = ({ setIsTooltipHovering(true)} + onPointerLeave={() => setIsTooltipHovering(false)} >
{capitalizeFirstLetter(featureType)} Feature @@ -163,7 +173,7 @@ export const FeatureBadge: FC = ({

This is {getGrammaticalArticle(featureType)} {featureType} feature. It - has not yet been marked for general availability. + has not yet reached generally availability (GA).

= ({ horizontal = "left", + onPointerEnter, + onPointerLeave, ...popoverProps }) => { const popover = usePopover(); @@ -155,7 +158,7 @@ export const PopoverContent: FC = ({ }, }} {...horizontalProps(horizontal)} - {...modeProps(popover)} + {...modeProps(popover, onPointerEnter, onPointerLeave)} {...popoverProps} id={popover.id} open={popover.open} @@ -165,14 +168,20 @@ export const PopoverContent: FC = ({ ); }; -const modeProps = (popover: PopoverContextValue) => { +const modeProps = ( + popover: PopoverContextValue, + externalOnPointerEnter: PointerEventHandler | undefined, + externalOnPointerLeave: PointerEventHandler | undefined, +) => { if (popover.mode === "hover") { return { - onPointerEnter: () => { + onPointerEnter: (event: PointerEvent) => { popover.setOpen(true); + externalOnPointerEnter?.(event); }, - onPointerLeave: () => { + onPointerLeave: (event: PointerEvent) => { popover.setOpen(false); + externalOnPointerLeave?.(event); }, }; } From a98186479dec68ecd4e1a1dc0d25d3d6e955610d Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 13 Sep 2024 22:10:25 +0000 Subject: [PATCH 12/43] wip: commit progress on adding story for controlled variant --- .../FeatureBadge/FeatureBadge.stories.tsx | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 7326015b23dae..842dbebd0353d 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -1,5 +1,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { FeatureBadge } from "./FeatureBadge"; +import { useState } from "react"; +import { useTheme } from "@emotion/react"; const meta: Meta = { title: "components/FeatureBadge", @@ -43,3 +45,44 @@ export const LargeStaticBeta: Story = { variant: "static", }, }; + +export const HoverControlledByParent: Story = { + args: { + type: "experimental", + size: "sm", + }, + + decorators: (Story, context) => { + const theme = useTheme(); + const [isHovering, setIsHovering] = useState(false); + + return ( + + ); + }, +}; From f47d0598d7ee1ccb4ce5416a4ab2b1939595a5a3 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 16 Sep 2024 13:37:54 +0000 Subject: [PATCH 13/43] fix: sort imports --- site/src/components/FeatureBadge/FeatureBadge.stories.tsx | 4 ++-- site/src/components/FeatureBadge/FeatureBadge.tsx | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 842dbebd0353d..9143c130d809b 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -1,7 +1,7 @@ +import { useTheme } from "@emotion/react"; import type { Meta, StoryObj } from "@storybook/react"; -import { FeatureBadge } from "./FeatureBadge"; import { useState } from "react"; -import { useTheme } from "@emotion/react"; +import { FeatureBadge } from "./FeatureBadge"; const meta: Meta = { title: "components/FeatureBadge", diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 57ba3e05b754e..eeb160e622118 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -10,7 +10,6 @@ import { type HTMLAttributes, type ReactNode, } from "react"; -import tailwindColors from "theme/tailwindColors"; import { docs } from "utils/docs"; /** From ad61763536431103318b6a1295392e3f9c8c2660 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 16 Sep 2024 13:50:20 +0000 Subject: [PATCH 14/43] refactor: change component API to be more obvious/ergonomic --- .../FeatureBadge/FeatureBadge.stories.tsx | 3 +- .../components/FeatureBadge/FeatureBadge.tsx | 54 ++++++++++--------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 9143c130d809b..714b461ea4140 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -79,7 +79,8 @@ export const HoverControlledByParent: Story = { {Story({ args: { ...context.initialArgs, - variant: isHovering ? "staticHover" : "static", + variant: "static", + highlighted: isHovering, }, })} diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index eeb160e622118..208f6f1c9db22 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -77,29 +77,43 @@ const styles = { }, } as const satisfies Record>; +function grammaticalArticle(nextWord: string): string { + const vowels = ["a", "e", "i", "o", "u"]; + const firstLetter = nextWord.slice(0, 1).toLowerCase(); + return vowels.includes(firstLetter) ? "an" : "a"; +} + +function capitalizeFirstLetter(text: string): string { + return text.slice(0, 1).toUpperCase() + text.slice(1); +} + type FeatureBadgeProps = Readonly< Omit, "children"> & { type: keyof typeof featureBadgeTypes; size?: "sm" | "lg"; - - /** - * Defines how the FeatureBadge should render. - * - interactive (default) - The badge functions like a link and - * controls its own hover styling. - * - static - The badge is completely static and has no interaction - * behavior. - * - staticHover - The badge is completely static, but displays badge - hover styling (but nothing related to links). Useful if you want a - parent component to control the hover styling. - */ - variant?: "interactive" | "static" | "staticHover"; - } + } & ( + | { + /** + * Defines whether the FeatureBadge should act as a + * controlled or uncontrolled component with its hover and + * general interaction styling. + */ + variant: "interactive"; + + // Had to specify the highlighted key for this union option + // even though it won't be used, because otherwise the type + // ergonomics for users would be too clunky. + highlighted?: undefined; + } + | { variant: "static"; highlighted?: boolean } + ) >; export const FeatureBadge: FC = ({ type, size = "sm", variant = "interactive", + highlighted = false, onPointerEnter, onPointerLeave, ...delegatedProps @@ -121,7 +135,7 @@ export const FeatureBadge: FC = ({ const featureType = featureBadgeTypes[type]; const showBadgeHoverStyle = - variant === "staticHover" || + highlighted || (variant === "interactive" && (isBadgeHovering || isTooltipHovering)); const coreContent = ( @@ -171,7 +185,7 @@ export const FeatureBadge: FC = ({

- This is {getGrammaticalArticle(featureType)} {featureType} feature. It + This is {grammaticalArticle(featureType)} {featureType} feature. It has not yet reached generally availability (GA).

@@ -188,13 +202,3 @@ export const FeatureBadge: FC = ({ ); }; - -function getGrammaticalArticle(nextWord: string): string { - const vowels = ["a", "e", "i", "o", "u"]; - const firstLetter = nextWord.slice(0, 1).toLowerCase(); - return vowels.includes(firstLetter) ? "an" : "a"; -} - -function capitalizeFirstLetter(text: string): string { - return text.slice(0, 1).toUpperCase() + text.slice(1); -} From 6e16aaabb0f2a8a9650450d6d81c75e87f8deabd Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 16 Sep 2024 13:54:37 +0000 Subject: [PATCH 15/43] fix: add biome-ignore comments to more base files --- site/src/components/Popover/Popover.tsx | 1 + site/src/theme/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/site/src/components/Popover/Popover.tsx b/site/src/components/Popover/Popover.tsx index 0e12728667537..8b4479d95b3a4 100644 --- a/site/src/components/Popover/Popover.tsx +++ b/site/src/components/Popover/Popover.tsx @@ -1,5 +1,6 @@ import MuiPopover, { type PopoverProps as MuiPopoverProps, + // biome-ignore lint/nursery/noRestrictedImports: This is the base component that our custom popover is based on } from "@mui/material/Popover"; import { type FC, diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts index 7516fe1207929..3079ce01b27a3 100644 --- a/site/src/theme/index.ts +++ b/site/src/theme/index.ts @@ -1,3 +1,4 @@ +// biome-ignore lint/nursery/noRestrictedImports: Have to use MUI styles as base import type { Theme as MuiTheme } from "@mui/material/styles"; import type * as monaco from "monaco-editor"; import type { Branding } from "./branding"; From 6a19b611ab02128674f9a460f2becfbd6aee0c7b Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 16 Sep 2024 13:59:54 +0000 Subject: [PATCH 16/43] fix: update import order again --- site/src/components/FeatureBadge/FeatureBadge.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 208f6f1c9db22..75b7c15045cde 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -4,11 +4,11 @@ import { visuallyHidden } from "@mui/utils"; import { HelpTooltipContent } from "components/HelpTooltip/HelpTooltip"; import { Popover, PopoverTrigger } from "components/Popover/Popover"; import { - useEffect, - useState, type FC, type HTMLAttributes, type ReactNode, + useEffect, + useState, } from "react"; import { docs } from "utils/docs"; From a2338673b592a6459c49373292d3568044b0c536 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 16 Sep 2024 14:03:30 +0000 Subject: [PATCH 17/43] chore: revert biome-ignore comment --- site/src/theme/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/theme/index.ts b/site/src/theme/index.ts index 3079ce01b27a3..8509ccb4135a6 100644 --- a/site/src/theme/index.ts +++ b/site/src/theme/index.ts @@ -1,4 +1,4 @@ -// biome-ignore lint/nursery/noRestrictedImports: Have to use MUI styles as base +// biome-ignore lint/nursery/noRestrictedImports: We still use `Theme` as a basis for our actual theme, for now. import type { Theme as MuiTheme } from "@mui/material/styles"; import type * as monaco from "monaco-editor"; import type { Branding } from "./branding"; From 7e1ec68e89ad7d961e9e72a78f18d6060cd9a0e3 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 17:05:28 +0000 Subject: [PATCH 18/43] chore: update body text for tooltip --- .../components/FeatureBadge/FeatureBadge.tsx | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 75b7c15045cde..717db0505435d 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -77,16 +77,6 @@ const styles = { }, } as const satisfies Record>; -function grammaticalArticle(nextWord: string): string { - const vowels = ["a", "e", "i", "o", "u"]; - const firstLetter = nextWord.slice(0, 1).toLowerCase(); - return vowels.includes(firstLetter) ? "an" : "a"; -} - -function capitalizeFirstLetter(text: string): string { - return text.slice(0, 1).toUpperCase() + text.slice(1); -} - type FeatureBadgeProps = Readonly< Omit, "children"> & { type: keyof typeof featureBadgeTypes; @@ -94,10 +84,21 @@ type FeatureBadgeProps = Readonly< } & ( | { /** - * Defines whether the FeatureBadge should act as a - * controlled or uncontrolled component with its hover and - * general interaction styling. + * Defines whether the FeatureBadge should respond directly + * to user input (displaying tooltips, controlling its own + * hover styling, etc.) + */ + variant: "static"; + + /** + * When used with the static variant, this lets you define + * whether the component should display hover/highlighted + * styling. Useful for coordinating hover behavior with an + * outside component. */ + highlighted?: boolean; + } + | { variant: "interactive"; // Had to specify the highlighted key for this union option @@ -105,7 +106,6 @@ type FeatureBadgeProps = Readonly< // ergonomics for users would be too clunky. highlighted?: undefined; } - | { variant: "static"; highlighted?: boolean } ) >; @@ -180,13 +180,8 @@ export const FeatureBadge: FC = ({ onPointerEnter={() => setIsTooltipHovering(true)} onPointerLeave={() => setIsTooltipHovering(false)} > -
- {capitalizeFirstLetter(featureType)} Feature -
-

- This is {grammaticalArticle(featureType)} {featureType} feature. It - has not yet reached generally availability (GA). + This feature has not yet reached general availability (GA).

Date: Tue, 17 Sep 2024 17:20:12 +0000 Subject: [PATCH 19/43] chore: update dark preivew role to use sky palette --- site/src/theme/dark/roles.ts | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/site/src/theme/dark/roles.ts b/site/src/theme/dark/roles.ts index dfefd1d10909b..6f11e83cd0d22 100644 --- a/site/src/theme/dark/roles.ts +++ b/site/src/theme/dark/roles.ts @@ -143,32 +143,33 @@ const roles: Roles = { }, }, preview: { - background: colors.cyan[950], - outline: colors.cyan[600], - text: colors.cyan[400], + background: colors.sky[950], + outline: colors.sky[400], + text: colors.sky[400], fill: { - solid: colors.cyan[400], - outline: colors.cyan[400], + solid: colors.sky[400], + outline: colors.sky[500], text: colors.white, }, hover: { background: colors.zinc[950], - outline: colors.cyan[500], - text: colors.cyan[300], + outline: colors.sky[500], + text: colors.sky[400], + fill: { text: colors.white, - outline: colors.cyan[600], - solid: colors.cyan[600], + outline: colors.sky[600], + solid: colors.sky[600], }, }, disabled: { - background: colors.zinc[950], - outline: colors.cyan[500], - text: colors.cyan[300], + background: colors.sky[950], + outline: colors.sky[800], + text: colors.sky[800], fill: { text: colors.white, - outline: colors.cyan[600], - solid: colors.cyan[600], + outline: colors.sky[600], + solid: colors.sky[600], }, }, }, From ebc5397ef2387d7285fbbb1707a7f4ce61950129 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 17:29:34 +0000 Subject: [PATCH 20/43] chore: update color palettes for light/darkBlue themes --- site/src/theme/darkBlue/roles.ts | 29 +++++++++++++++-------------- site/src/theme/light/roles.ts | 30 +++++++++++++++--------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/site/src/theme/darkBlue/roles.ts b/site/src/theme/darkBlue/roles.ts index a0f36daa810b9..8d955687737e8 100644 --- a/site/src/theme/darkBlue/roles.ts +++ b/site/src/theme/darkBlue/roles.ts @@ -143,32 +143,33 @@ const roles: Roles = { }, }, preview: { - background: colors.cyan[950], - outline: colors.cyan[600], - text: colors.cyan[400], + background: colors.sky[950], + outline: colors.sky[400], + text: colors.sky[400], fill: { - solid: colors.cyan[400], - outline: colors.cyan[400], + solid: colors.sky[400], + outline: colors.sky[500], text: colors.white, }, hover: { background: colors.zinc[950], - outline: colors.cyan[500], - text: colors.cyan[300], + outline: colors.sky[500], + text: colors.sky[400], + fill: { text: colors.white, - outline: colors.cyan[600], - solid: colors.cyan[600], + outline: colors.sky[600], + solid: colors.sky[600], }, }, disabled: { - background: colors.zinc[950], - outline: colors.cyan[500], - text: colors.cyan[300], + background: colors.sky[950], + outline: colors.sky[800], + text: colors.sky[800], fill: { text: colors.white, - outline: colors.cyan[600], - solid: colors.cyan[600], + outline: colors.sky[600], + solid: colors.sky[600], }, }, }, diff --git a/site/src/theme/light/roles.ts b/site/src/theme/light/roles.ts index 905d45384f247..ea2bef0454ed5 100644 --- a/site/src/theme/light/roles.ts +++ b/site/src/theme/light/roles.ts @@ -143,31 +143,31 @@ const roles: Roles = { }, }, preview: { - background: colors.cyan[100], - outline: colors.cyan[500], - text: colors.cyan[950], + background: colors.sky[50], + outline: colors.sky[700], + text: colors.sky[700], fill: { - solid: colors.cyan[600], - outline: colors.cyan[600], + solid: colors.sky[600], + outline: colors.sky[700], text: colors.white, }, hover: { - background: colors.cyan[50], - outline: colors.cyan[600], - text: colors.cyan[950], + background: colors.zinc[50], + outline: colors.sky[700], + text: colors.sky[700], fill: { - outline: colors.cyan[500], - solid: colors.cyan[500], + outline: colors.sky[500], + solid: colors.sky[500], text: colors.white, }, }, disabled: { - background: colors.cyan[50], - outline: colors.cyan[800], - text: colors.cyan[200], + background: colors.sky[50], + outline: colors.sky[800], + text: colors.sky[200], fill: { - solid: colors.cyan[800], - outline: colors.cyan[800], + solid: colors.sky[800], + outline: colors.sky[800], text: colors.white, }, }, From a9b68978bd06cfe50345fc1979b85b991692ba6e Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 17:59:56 +0000 Subject: [PATCH 21/43] chore: add beta badge to organizations subheader --- .vscode/settings.json | 1 + .../components/FeatureBadge/FeatureBadge.tsx | 1 + .../ManagementSettingsPage/SidebarView.tsx | 22 ++++++++++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 82ce10e888010..b3f595bde2d94 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -120,6 +120,7 @@ "stretchr", "STTY", "stuntest", + "subpage", "tailbroker", "tailcfg", "tailexchange", diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 717db0505435d..fbffc7aea5e58 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -34,6 +34,7 @@ const styles = { cursor: "default", flexShrink: 0, + alignSelf: "baseline", padding: "4px 8px", lineHeight: 1, whiteSpace: "nowrap", diff --git a/site/src/pages/ManagementSettingsPage/SidebarView.tsx b/site/src/pages/ManagementSettingsPage/SidebarView.tsx index 795458794bc53..6da392fa221ad 100644 --- a/site/src/pages/ManagementSettingsPage/SidebarView.tsx +++ b/site/src/pages/ManagementSettingsPage/SidebarView.tsx @@ -7,6 +7,7 @@ import type { Experiments, Organization, } from "api/typesGenerated"; +import { FeatureBadge } from "components/FeatureBadge/FeatureBadge"; import { Loader } from "components/Loader/Loader"; import { Sidebar as BaseSidebar } from "components/Sidebar/Sidebar"; import { Stack } from "components/Stack/Stack"; @@ -47,7 +48,10 @@ export const SidebarView: FC = ({ // TODO: Do something nice to scroll to the active org. return ( -
Deployment
+
+

Deployment

+
+ -
Organizations
+
+

Organizations

+ +
+ {permissions.createOrganization && ( = ({ const styles = { sidebarHeader: { textTransform: "uppercase", - letterSpacing: "0.15em", + letterSpacing: "0.1em", + margin: 0, fontSize: 11, fontWeight: 500, paddingBottom: 4, From 31e1fa7790a4c8ba8125030d11a96203a215e2c2 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 18:08:38 +0000 Subject: [PATCH 22/43] chore: add beta badge to organizations settings page --- site/src/components/FeatureBadge/FeatureBadge.tsx | 1 - site/src/components/SettingsHeader/SettingsHeader.tsx | 3 ++- .../ManagementSettingsPage/OrganizationSettingsPageView.tsx | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index fbffc7aea5e58..717db0505435d 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -34,7 +34,6 @@ const styles = { cursor: "default", flexShrink: 0, - alignSelf: "baseline", padding: "4px 8px", lineHeight: 1, whiteSpace: "nowrap", diff --git a/site/src/components/SettingsHeader/SettingsHeader.tsx b/site/src/components/SettingsHeader/SettingsHeader.tsx index ea68415cc1e5b..1dec847e65093 100644 --- a/site/src/components/SettingsHeader/SettingsHeader.tsx +++ b/site/src/components/SettingsHeader/SettingsHeader.tsx @@ -31,7 +31,7 @@ export const SettingsHeader: FC = ({ fontSize: 32, fontWeight: 700, display: "flex", - alignItems: "center", + alignItems: "baseline", lineHeight: "initial", margin: 0, marginBottom: 4, @@ -47,6 +47,7 @@ export const SettingsHeader: FC = ({ {tooltip} + {description && ( - + } + /> {Boolean(error) && !isApiValidationError(error) && (
From e16b140ab5c2b71a622a5dc2d359544715b92d86 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 18:11:03 +0000 Subject: [PATCH 23/43] chore: beef up font weight for form header --- site/src/components/Form/Form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/components/Form/Form.tsx b/site/src/components/Form/Form.tsx index 286c307b6231b..7286e0df1e700 100644 --- a/site/src/components/Form/Form.tsx +++ b/site/src/components/Form/Form.tsx @@ -170,7 +170,7 @@ const styles = { formSectionInfoTitle: (theme) => ({ fontSize: 20, color: theme.palette.text.primary, - fontWeight: 400, + fontWeight: 500, margin: 0, marginBottom: 8, display: "flex", From 3aeb3c0f2ce41744f92b981f19a57a888ee5d963 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 18:20:52 +0000 Subject: [PATCH 24/43] fix: update text contrast for org menu list --- site/src/pages/ManagementSettingsPage/SidebarView.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/site/src/pages/ManagementSettingsPage/SidebarView.tsx b/site/src/pages/ManagementSettingsPage/SidebarView.tsx index 6da392fa221ad..22a17e6afa9f3 100644 --- a/site/src/pages/ManagementSettingsPage/SidebarView.tsx +++ b/site/src/pages/ManagementSettingsPage/SidebarView.tsx @@ -412,7 +412,7 @@ const classNames = { `, subLink: (css, theme) => css` - color: inherit; + color: ${theme.palette.text.secondary}; text-decoration: none; display: block; @@ -429,7 +429,8 @@ const classNames = { } `, - activeSubLink: (css) => css` + activeSubLink: (css, theme) => css` + color: ${theme.palette.text.primary}; font-weight: 600; `, } satisfies Record; From 71323ac25f1a8aa2ace9d6e832a65ca51d6c79c5 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 18:37:41 +0000 Subject: [PATCH 25/43] chore: add beta badge to deployment dropdown --- site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx b/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx index 1efff049b1f39..76d1945a40418 100644 --- a/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx +++ b/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx @@ -2,6 +2,7 @@ import { type Interpolation, type Theme, css, useTheme } from "@emotion/react"; import Button from "@mui/material/Button"; import MenuItem from "@mui/material/MenuItem"; import { DropdownArrow } from "components/DropdownArrow/DropdownArrow"; +import { FeatureBadge } from "components/FeatureBadge/FeatureBadge"; import { Popover, PopoverContent, @@ -109,6 +110,7 @@ const DeploymentDropdownContent: FC = ({ onClick={onPopoverClose} > Organizations + )} {canViewAllUsers && ( @@ -149,7 +151,7 @@ const styles = { menuItem: (theme) => css` text-decoration: none; color: inherit; - gap: 20px; + gap: 8px; padding: 8px 20px; font-size: 14px; From da31c8411064a9fd65e7c9c742ca29fd1d5e2256 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 18:38:21 +0000 Subject: [PATCH 26/43] fix: run biome on imports --- .../ManagementSettingsPage/OrganizationSettingsPageView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx index eee7a3a3936f2..783c4b6f0c419 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPageView.tsx @@ -8,6 +8,7 @@ import type { } from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"; +import { FeatureBadge } from "components/FeatureBadge/FeatureBadge"; import { FormFields, FormFooter, @@ -26,7 +27,6 @@ import { } from "utils/formUtils"; import * as Yup from "yup"; import { HorizontalContainer, HorizontalSection } from "./Horizontal"; -import { FeatureBadge } from "components/FeatureBadge/FeatureBadge"; const MAX_DESCRIPTION_CHAR_LIMIT = 128; const MAX_DESCRIPTION_MESSAGE = `Please enter a description that is no longer than ${MAX_DESCRIPTION_CHAR_LIMIT} characters.`; From c7308c3f23dddd3eb154fc43e5288a6016f438b8 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 17 Sep 2024 18:51:14 +0000 Subject: [PATCH 27/43] chore: remove API for controlling FeatureBadge hover styling externally --- .../FeatureBadge/FeatureBadge.stories.tsx | 44 ------------------- .../components/FeatureBadge/FeatureBadge.tsx | 32 ++------------ 2 files changed, 3 insertions(+), 73 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 714b461ea4140..7326015b23dae 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -1,6 +1,4 @@ -import { useTheme } from "@emotion/react"; import type { Meta, StoryObj } from "@storybook/react"; -import { useState } from "react"; import { FeatureBadge } from "./FeatureBadge"; const meta: Meta = { @@ -45,45 +43,3 @@ export const LargeStaticBeta: Story = { variant: "static", }, }; - -export const HoverControlledByParent: Story = { - args: { - type: "experimental", - size: "sm", - }, - - decorators: (Story, context) => { - const theme = useTheme(); - const [isHovering, setIsHovering] = useState(false); - - return ( - - ); - }, -}; diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 717db0505435d..da2c5e3d66b4c 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -81,39 +81,14 @@ type FeatureBadgeProps = Readonly< Omit, "children"> & { type: keyof typeof featureBadgeTypes; size?: "sm" | "lg"; - } & ( - | { - /** - * Defines whether the FeatureBadge should respond directly - * to user input (displaying tooltips, controlling its own - * hover styling, etc.) - */ - variant: "static"; - - /** - * When used with the static variant, this lets you define - * whether the component should display hover/highlighted - * styling. Useful for coordinating hover behavior with an - * outside component. - */ - highlighted?: boolean; - } - | { - variant: "interactive"; - - // Had to specify the highlighted key for this union option - // even though it won't be used, because otherwise the type - // ergonomics for users would be too clunky. - highlighted?: undefined; - } - ) + variant: "interactive" | "static"; + } >; export const FeatureBadge: FC = ({ type, size = "sm", variant = "interactive", - highlighted = false, onPointerEnter, onPointerLeave, ...delegatedProps @@ -135,8 +110,7 @@ export const FeatureBadge: FC = ({ const featureType = featureBadgeTypes[type]; const showBadgeHoverStyle = - highlighted || - (variant === "interactive" && (isBadgeHovering || isTooltipHovering)); + variant === "interactive" && (isBadgeHovering || isTooltipHovering); const coreContent = ( Date: Tue, 17 Sep 2024 19:15:37 +0000 Subject: [PATCH 28/43] chore: add xs size for badge --- .../components/FeatureBadge/FeatureBadge.stories.tsx | 11 +++++++++++ site/src/components/FeatureBadge/FeatureBadge.tsx | 7 ++++++- .../modules/dashboard/Navbar/DeploymentDropdown.tsx | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx index 7326015b23dae..650c97b9198a9 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.stories.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.stories.tsx @@ -43,3 +43,14 @@ export const LargeStaticBeta: Story = { variant: "static", }, }; + +// While it's possible, we shouldn't use the xs size with the interactive +// variant, because then the badge might be too small for users with motor +// control issues to get their hand to hover over the target reliably +export const ExtraSmallStaticBeta: Story = { + args: { + type: "beta", + size: "xs", + variant: "static", + }, +}; diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index da2c5e3d66b4c..74f3ffca136c1 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -55,6 +55,10 @@ const styles = { fontSize: "1rem", }, + badgeExtraSmallText: { + fontSize: "0.625rem", + }, + tooltipTitle: (theme) => ({ color: theme.palette.text.primary, fontWeight: 600, @@ -80,7 +84,7 @@ const styles = { type FeatureBadgeProps = Readonly< Omit, "children"> & { type: keyof typeof featureBadgeTypes; - size?: "sm" | "lg"; + size?: "xs" | "sm" | "lg"; variant: "interactive" | "static"; } >; @@ -116,6 +120,7 @@ export const FeatureBadge: FC = ({ = ({ onClick={onPopoverClose} > Organizations - + )} {canViewAllUsers && ( From fb4b734eda301001d53c71fb9548e32a15dbc8a0 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 18 Sep 2024 14:51:19 +0000 Subject: [PATCH 29/43] fix: update font weight for xs feature badges --- site/src/components/FeatureBadge/FeatureBadge.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/src/components/FeatureBadge/FeatureBadge.tsx b/site/src/components/FeatureBadge/FeatureBadge.tsx index 74f3ffca136c1..0a95fd0541015 100644 --- a/site/src/components/FeatureBadge/FeatureBadge.tsx +++ b/site/src/components/FeatureBadge/FeatureBadge.tsx @@ -56,6 +56,9 @@ const styles = { }, badgeExtraSmallText: { + // Have to beef up font weight so that the letters still maintain the + // same relative thickness as all our other main UI text + fontWeight: 500, fontSize: "0.625rem", }, From 5a7bbd3340f0b07fa45bcb4db0e6b798ceae1be0 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 18 Sep 2024 14:56:38 +0000 Subject: [PATCH 30/43] chore: add beta badges to all org headers --- .../SettingsHeader/SettingsHeader.tsx | 2 +- .../dashboard/Navbar/DeploymentDropdown.tsx | 2 -- .../CustomRolesPage/CustomRolesPage.tsx | 2 ++ .../GroupsPage/GroupsPage.tsx | 2 ++ .../IdpSyncPage/IdpSyncPage.tsx | 8 ++++- .../OrganizationMembersPageView.tsx | 6 +++- .../OrganizationProvisionersPageView.tsx | 34 +++++++++++-------- .../ManagementSettingsPage/SidebarView.tsx | 2 +- 8 files changed, 37 insertions(+), 21 deletions(-) diff --git a/site/src/components/SettingsHeader/SettingsHeader.tsx b/site/src/components/SettingsHeader/SettingsHeader.tsx index 1dec847e65093..6fc332153a9d1 100644 --- a/site/src/components/SettingsHeader/SettingsHeader.tsx +++ b/site/src/components/SettingsHeader/SettingsHeader.tsx @@ -24,7 +24,7 @@ export const SettingsHeader: FC = ({ return (
- +

= ({ onClick={onPopoverClose} > Organizations - )} {canViewAllUsers && ( diff --git a/site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx b/site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx index beff71098fbac..0576b828a203e 100644 --- a/site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx +++ b/site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx @@ -17,6 +17,7 @@ import { Link as RouterLink, useParams } from "react-router-dom"; import { pageTitle } from "utils/page"; import { useOrganizationSettings } from "../ManagementSettingsLayout"; import CustomRolesPageView from "./CustomRolesPageView"; +import { FeatureBadge } from "components/FeatureBadge/FeatureBadge"; export const CustomRolesPage: FC = () => { const queryClient = useQueryClient(); @@ -66,6 +67,7 @@ export const CustomRolesPage: FC = () => { } /> {permissions.assignOrgRole && isCustomRolesEnabled && ( - } + - Provisioners - + } + /> + + + {provisioners.map((provisioner) => ( diff --git a/site/src/pages/ManagementSettingsPage/SidebarView.tsx b/site/src/pages/ManagementSettingsPage/SidebarView.tsx index 22a17e6afa9f3..4a6f8f0ef8e68 100644 --- a/site/src/pages/ManagementSettingsPage/SidebarView.tsx +++ b/site/src/pages/ManagementSettingsPage/SidebarView.tsx @@ -203,7 +203,7 @@ const OrganizationsSettingsNavigation: FC< }} >

Organizations

- + {permissions.createOrganization && ( From 66389420f59c3cdba4f2e124a7df0fda5ae4951c Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Wed, 18 Sep 2024 15:59:10 +0000 Subject: [PATCH 31/43] fix: turn badges and tooltips into separate concerns --- .../SettingsHeader/SettingsHeader.tsx | 49 ++++++++++--------- .../CustomRolesPage/CustomRolesPage.tsx | 2 +- .../GroupsPage/GroupsPage.tsx | 2 +- .../IdpSyncPage/IdpSyncPage.tsx | 8 +-- .../OrganizationMembersPageView.tsx | 2 +- .../OrganizationProvisionersPageView.tsx | 2 +- .../OrganizationSettingsPageView.tsx | 2 +- 7 files changed, 34 insertions(+), 33 deletions(-) diff --git a/site/src/components/SettingsHeader/SettingsHeader.tsx b/site/src/components/SettingsHeader/SettingsHeader.tsx index 6fc332153a9d1..30ed5b0c527a0 100644 --- a/site/src/components/SettingsHeader/SettingsHeader.tsx +++ b/site/src/components/SettingsHeader/SettingsHeader.tsx @@ -10,6 +10,7 @@ interface HeaderProps { secondary?: boolean; docsHref?: string; tooltip?: ReactNode; + badges?: ReactNode; } export const SettingsHeader: FC = ({ @@ -18,34 +19,38 @@ export const SettingsHeader: FC = ({ docsHref, secondary, tooltip, + badges, }) => { const theme = useTheme(); return (
- -

- {title} -

- {tooltip} + + +

+ {title} +

+ {tooltip} +
+ {badges}
{description && ( diff --git a/site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx b/site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx index 0576b828a203e..b8cb1fb7387b2 100644 --- a/site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx +++ b/site/src/pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage.tsx @@ -67,7 +67,7 @@ export const CustomRolesPage: FC = () => { } + badges={} /> {permissions.assignOrgRole && isCustomRolesEnabled && (