From 5a0766e311e5879d90b9d412e3f71509fdbd9d96 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 6 May 2026 16:18:09 -0300 Subject: [PATCH 01/13] fix(button): drop iconLeft/iconRight props, icons compose via children MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The icon-spacing issue (originally PR #7402) had multiple root causes: the iconLeft/iconRight prop API created a separate render path from the children-based pattern that production code mostly uses, and patching one path's spacing repeatedly caused regressions in the other. Removing the prop API entirely is the cleaner fix — there's now one render path for icons, and spacing is handled by the button's flex+gap wrapper. Changes: - Remove iconLeft/iconRight/iconLeftColour/iconRightColour/iconSize props (and the local iconColours map) from Button.tsx. - Single content wrapper for both - @@ -130,20 +131,47 @@ export const WithIcons: Story = { docs: { description: { story: - 'Buttons support `iconLeft` and `iconRight` props. Pass any `IconName` from the icon system.', + 'Icons compose via children — pass `` JSX directly. Spacing between icon and label is handled by the button wrapper (`display: flex; gap: 0.5rem`).', }, }, }, render: () => (
- - - +
+ ), +} + +export const IconOnly: Story = { + parameters: { + docs: { + description: { + story: + 'Icon-only buttons via `theme="icon"` (32×32) or `className="btn-with-icon"` (table-row affordances). Pass the icon as children.', + }, + }, + }, + render: () => ( +
+ + +
), diff --git a/frontend/web/components/EditIdentity.tsx b/frontend/web/components/EditIdentity.tsx index e614fc12e615..26664ae3246b 100644 --- a/frontend/web/components/EditIdentity.tsx +++ b/frontend/web/components/EditIdentity.tsx @@ -2,6 +2,7 @@ import React, { FC, useEffect, useRef, useState } from 'react' import { Identity } from 'common/types/responses' import { useUpdateIdentityMutation } from 'common/services/useIdentity' import Button from './base/forms/Button' +import { Icon } from './icons' import ErrorMessage from './ErrorMessage' import GhostInput from './base/forms/GhostInput' @@ -62,15 +63,13 @@ const EditIdentity: FC = ({ data, environmentId }) => { /> {error} diff --git a/frontend/web/components/GoogleButton.tsx b/frontend/web/components/GoogleButton.tsx index 0ba3b208a811..2c3eab18e5ee 100644 --- a/frontend/web/components/GoogleButton.tsx +++ b/frontend/web/components/GoogleButton.tsx @@ -1,6 +1,7 @@ import React, { FC } from 'react' import { TokenResponse, useGoogleLogin } from '@react-oauth/google' import Button from './base/forms/Button' +import { Icon } from './icons' type GoogleButtonProps = { className?: string @@ -22,10 +23,10 @@ const GoogleButton: FC = ({ className, onSuccess }) => { ) diff --git a/frontend/web/components/JSONReference.tsx b/frontend/web/components/JSONReference.tsx index 017cc3120809..53ab4463328c 100644 --- a/frontend/web/components/JSONReference.tsx +++ b/frontend/web/components/JSONReference.tsx @@ -5,7 +5,7 @@ import Highlight from './Highlight' import Button from './base/forms/Button' import Switch from './Switch' import flagsmith from '@flagsmith/flagsmith' -import Icon from './icons/Icon' +import { Icon } from './icons' import Utils from 'common/utils/utils' type JSONReferenceType = { @@ -146,9 +146,8 @@ const JSONReference: FC = ({ Utils.copyToClipboard(condensed ? idsOnly : value) }} size='xSmall' - iconLeft='copy' - iconLeftColour='white' > + Copy JSON diff --git a/frontend/web/components/base/forms/Button.tsx b/frontend/web/components/base/forms/Button.tsx index 18f941483b4b..4101e2930bb2 100644 --- a/frontend/web/components/base/forms/Button.tsx +++ b/frontend/web/components/base/forms/Button.tsx @@ -1,14 +1,6 @@ import React from 'react' import cn from 'classnames' import { ButtonHTMLAttributes, HTMLAttributeAnchorTarget } from 'react' -import Icon, { IconName } from 'components/icons/Icon' - -const iconColours = { - primary: '#6837fc', - white: '#ffffff', -} as const - -export type IconColour = keyof typeof iconColours export const themeClassNames = { danger: 'btn btn-danger', @@ -31,15 +23,10 @@ export const sizeClassNames = { } export type ButtonType = ButtonHTMLAttributes & { - iconRight?: IconName - iconRightColour?: IconColour - iconLeftColour?: IconColour - iconLeft?: IconName href?: string target?: HTMLAttributeAnchorTarget theme?: keyof typeof themeClassNames size?: keyof typeof sizeClassNames - iconSize?: number } export const Button = React.forwardRef< @@ -51,11 +38,6 @@ export const Button = React.forwardRef< children, className, href, - iconLeft, - iconLeftColour, - iconRight, - iconRightColour, - iconSize = 24, onMouseUp, size = 'default', target, @@ -65,6 +47,11 @@ export const Button = React.forwardRef< }, ref, ) => { + const content = ( + + {children} + + ) return href ? (
} > -
- {!!iconLeft && ( - - )} - {children} -
- {!!iconRight && ( - - )} + {content}
) : ( ) }, diff --git a/frontend/web/components/icons/index.ts b/frontend/web/components/icons/index.ts new file mode 100644 index 000000000000..906700268806 --- /dev/null +++ b/frontend/web/components/icons/index.ts @@ -0,0 +1,2 @@ +export { default as Icon } from './Icon' +export type { IconName } from './Icon' diff --git a/frontend/web/components/modals/base/ModalConfirm.tsx b/frontend/web/components/modals/base/ModalConfirm.tsx index c885d7c7cc1f..80c5e7df613a 100644 --- a/frontend/web/components/modals/base/ModalConfirm.tsx +++ b/frontend/web/components/modals/base/ModalConfirm.tsx @@ -1,5 +1,6 @@ import { Modal, ModalBody, ModalFooter } from 'reactstrap' import Button from 'components/base/forms/Button' +import { Icon } from 'components/icons' import React, { FC, ReactNode } from 'react' import ModalHeader from './ModalHeader' import ModalHR from 'components/modals/ModalHR' @@ -68,10 +69,10 @@ const Confirm: FC = ({ theme='danger' id='confirm-btn-yes' disabled={disabled || disabledYes} - iconRight='fas fa-trash' onClick={yes} > {yesText} + ) : ( diff --git a/frontend/web/components/pages/HomePage.tsx b/frontend/web/components/pages/HomePage.tsx index d0e3f941edd4..a575b45cda19 100644 --- a/frontend/web/components/pages/HomePage.tsx +++ b/frontend/web/components/pages/HomePage.tsx @@ -11,6 +11,7 @@ import Button from 'components/base/forms/Button' import PasswordRequirements from 'components/PasswordRequirements' import { informationCircleOutline } from 'ionicons/icons' import { IonIcon } from '@ionic/react' +import { Icon } from 'components/icons' import classNames from 'classnames' import InfoMessage from 'components/InfoMessage' import OnboardingPage from './OnboardingPage' @@ -206,9 +207,9 @@ const HomePage: React.FC = () => { , diff --git a/frontend/web/components/release-pipelines/PipelineStageActions.tsx b/frontend/web/components/release-pipelines/PipelineStageActions.tsx index 59f2457f7953..c6867e214d8b 100644 --- a/frontend/web/components/release-pipelines/PipelineStageActions.tsx +++ b/frontend/web/components/release-pipelines/PipelineStageActions.tsx @@ -4,6 +4,7 @@ import { StageActionBody, StageActionRequest } from 'common/types/requests' import { useMemo } from 'react' import SinglePipelineStageAction from './SinglePipelineStageAction' import Button from 'components/base/forms/Button' +import { Icon } from 'components/icons' import { StageActionType } from 'common/types/responses' interface PipelineStageActionsProps { @@ -60,7 +61,8 @@ const PipelineStageActions = ({ onRemoveAction={index > 0 ? onRemoveAction : undefined} /> ))} - From 0f51d3381b426bd8ca2f08b8ef435ebbc1babacf Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 6 May 2026 16:30:03 -0300 Subject: [PATCH 02/13] fix(button): only wrap children when icon+label spacing is needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit always wrapped Button children in a flex+gap span, which regressed icon-only callers (`btn-with-icon` rows like the identities trash button) and presentational containers (`btn-project` project tiles in ProjectManageWidget). For single children the wrapper is unnecessary — render children directly so callers' own layout isn't disturbed. The wrapper still applies when there are multiple children, which is the case the spacing fix targets (icon + label). Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/web/components/base/forms/Button.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/frontend/web/components/base/forms/Button.tsx b/frontend/web/components/base/forms/Button.tsx index 4101e2930bb2..e6b8cbcd60d3 100644 --- a/frontend/web/components/base/forms/Button.tsx +++ b/frontend/web/components/base/forms/Button.tsx @@ -47,11 +47,14 @@ export const Button = React.forwardRef< }, ref, ) => { - const content = ( - - {children} - - ) + const content = + React.Children.count(children) > 1 ? ( + + {children} + + ) : ( + children + ) return href ? ( Date: Wed, 6 May 2026 17:01:25 -0300 Subject: [PATCH 03/13] fix(modal-confirm): remove erroneous trash icon from danger confirm button The prior commit replaced an invalid `iconRight='fas fa-trash'` (a Font Awesome class string passed where the prop expected a project IconName, which silently rendered nothing in production) with ``. That introduced an oversized 24px icon that production never displayed. The right fix is to drop the icon entirely so the modal matches prod's behaviour. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/web/components/modals/base/ModalConfirm.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/web/components/modals/base/ModalConfirm.tsx b/frontend/web/components/modals/base/ModalConfirm.tsx index 80c5e7df613a..5c866168e5ef 100644 --- a/frontend/web/components/modals/base/ModalConfirm.tsx +++ b/frontend/web/components/modals/base/ModalConfirm.tsx @@ -1,6 +1,5 @@ import { Modal, ModalBody, ModalFooter } from 'reactstrap' import Button from 'components/base/forms/Button' -import { Icon } from 'components/icons' import React, { FC, ReactNode } from 'react' import ModalHeader from './ModalHeader' import ModalHR from 'components/modals/ModalHR' @@ -72,7 +71,6 @@ const Confirm: FC = ({ onClick={yes} > {yesText} - ) : ( - ), } diff --git a/frontend/web/components/base/forms/Button.tsx b/frontend/web/components/base/forms/Button.tsx index e6b8cbcd60d3..f630aabcd8f2 100644 --- a/frontend/web/components/base/forms/Button.tsx +++ b/frontend/web/components/base/forms/Button.tsx @@ -7,7 +7,6 @@ export const themeClassNames = { icon: 'btn-icon', outline: 'btn--outline', primary: 'btn-primary', - project: 'btn-project', secondary: 'btn btn-secondary', success: 'btn btn-success', tertiary: 'btn-tertiary', From b40e679269d8c72d08ab9647283019152360dd9e Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 6 May 2026 17:14:32 -0300 Subject: [PATCH 05/13] fix(buttons): use semantic icon tokens for btn-icon path fills MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .btn-icon resting/hover states hardcoded \$text-muted and \$body-color SCSS variables that didn't adapt between light and dark — leaving icons illegible against dark backgrounds (visible in the new IconOnly story). Replace with --color-icon-secondary (resting) and --color-icon-default (hover). Both tokens auto-resolve via CSS variables: slate-500/600 in light, slate-300/0 in dark — proper contrast in both modes. Drops the now-redundant path-fill overrides from the .dark block since the CSS vars handle the mode switch. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/web/styles/project/_buttons.scss | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/frontend/web/styles/project/_buttons.scss b/frontend/web/styles/project/_buttons.scss index 50bba7d7e9fe..aa2afa5bb731 100644 --- a/frontend/web/styles/project/_buttons.scss +++ b/frontend/web/styles/project/_buttons.scss @@ -152,12 +152,12 @@ button.btn { height: 18px; } path { - fill: $text-muted; + fill: var(--color-icon-secondary); } &:hover,&:focus { background-color: $bg-light300; path { - fill: $body-color; + fill: var(--color-icon-default); } } } @@ -349,14 +349,8 @@ $add-btn-size: 34px; } &.btn-icon { color: $body-color-dark; - path { - fill: $text-muted; - } &:hover,&:focus { background-color: $bg-dark300; - path { - fill: $body-color-dark; - } } } &.btn-secondary { From 9898e7a199901f01b4ec5b1372f41eb27524cd3d Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 6 May 2026 17:21:28 -0300 Subject: [PATCH 06/13] fix(buttons): give btn-with-icon a self-contained resting fill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The base \`.btn\` rule sets \`color: white\` as the default, which the \`btn-with-icon\` resting state silently inherits — so icons render white on the class's light-grey \`\$basic-alpha-8\` background in light mode (invisible) and white on the dark variant (visible by accident). Production callers compensate ad-hoc: some pass \`text-body\` className, others hardcode \`fill='#656D7B'\` on the Icon. Either escape works, but the class itself is fragile — drop the explicit fill on a caller and it falls into the white-on-grey case. Set \`svg path { fill: var(--color-icon-secondary) }\` on the resting state so the visual treatment is self-contained. Hover/focus rules keep their existing purple/body-color overrides — the resting fix is purely additive. Token auto-adapts: slate-500 in light, slate-300 in dark. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/web/styles/project/_buttons.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/web/styles/project/_buttons.scss b/frontend/web/styles/project/_buttons.scss index aa2afa5bb731..d9c607dc8c37 100644 --- a/frontend/web/styles/project/_buttons.scss +++ b/frontend/web/styles/project/_buttons.scss @@ -165,6 +165,9 @@ button.btn { padding: 0 14px; background-color: $basic-alpha-8; border-radius: $border-radius; + svg path { + fill: var(--color-icon-secondary); + } &:hover, &:active, &:disabled { From b24cb41a38edbf9dcbb212895c24a59ccf6183c5 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 7 May 2026 16:32:10 -0300 Subject: [PATCH 07/13] docs(button): tidy Storybook stories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the IconOnly story — it duplicated the `theme='icon'` example already in Variants and documented the `className='btn-with-icon'` hack as a Button feature, which it isn't (it's a className override that will be replaced by a future IconButton primitive). Also trim the related hint from the Variants description so it doesn't push readers toward `theme='icon'` for table actions. Add the missing `xxSmall` variant to the Sizes story so visual coverage matches `sizeClassNames`. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/Button.stories.tsx | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/frontend/documentation/components/Button.stories.tsx b/frontend/documentation/components/Button.stories.tsx index bf73768863b3..faefd321cbde 100644 --- a/frontend/documentation/components/Button.stories.tsx +++ b/frontend/documentation/components/Button.stories.tsx @@ -61,7 +61,7 @@ export const Variants: Story = { docs: { description: { story: - 'All available button themes. Use `primary` for main actions, `secondary` for alternatives, `outline` for low-emphasis actions, `danger` for destructive actions, and `success` for positive confirmations. `icon` is for icon-only buttons (copy, action triggers in tables).', + 'All available button themes. Use `primary` for main actions, `secondary` for alternatives, `outline` for low-emphasis actions, `danger` for destructive actions, and `success` for positive confirmations.', }, }, }, @@ -85,7 +85,7 @@ export const Sizes: Story = { parameters: { docs: { description: { - story: 'Button sizes from large to extra small.', + story: 'Button sizes from large to extra-extra small.', }, }, }, @@ -95,6 +95,7 @@ export const Sizes: Story = { + ), } @@ -151,27 +152,3 @@ export const WithIcons: Story = { ), } - -export const IconOnly: Story = { - parameters: { - docs: { - description: { - story: - 'Icon-only buttons via `theme="icon"` (32×32) or `className="btn-with-icon"` (table-row affordances). Pass the icon as children.', - }, - }, - }, - render: () => ( -
- - - -
- ), -} From c423c1d86c570de43e2c939cfabf210a33fd793d Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 7 May 2026 16:32:33 -0300 Subject: [PATCH 08/13] fix(buttons): switch .btn to inline-flex with hover and height fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch the project's `.btn` from Bootstrap-default `inline-block` to `inline-flex` with `align-items: center; justify-content: center; gap: 0.5rem`. This lets icon+label compositions space themselves via flex gap natively — no wrapper span needed — and centres icon-only buttons without the `mr/ml` margin trick that was the original spacing bug. `Button.tsx`'s conditional flex-wrapper goes away, and `themeClassNames` is normalised so `
` and ` ) }, diff --git a/frontend/web/styles/project/_buttons.scss b/frontend/web/styles/project/_buttons.scss index d9c607dc8c37..f5e4b8b0a4b6 100644 --- a/frontend/web/styles/project/_buttons.scss +++ b/frontend/web/styles/project/_buttons.scss @@ -2,21 +2,17 @@ .btn, button.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + height: $btn-line-height; white-space: nowrap; color: white; - // Project button, to remove with project select bar - &:hover, - &:focus { - background-color: $btn-hover-bg; - } &:focus-visible { box-shadow: none; } - &.btn:active { - background-color: $btn-active-bg; - } - &-link { color: $primary; &:hover, @@ -343,13 +339,6 @@ $add-btn-size: 34px; .dark { .btn { - &:hover, - &:focus { - background-color: $btn-hover-bg-dark; - } - &:active { - background-color: $primary; - } &.btn-icon { color: $body-color-dark; &:hover,&:focus { From e4822658af12d94888e249bf84679ab7c882a9f6 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 7 May 2026 15:26:21 -0300 Subject: [PATCH 09/13] fix(buttons): opt .btn-project out of new inline-flex layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `.btn-project` is the project picker tile — a 76px-tall surface whose letter+title layout is owned by the inner ``, not by the outer button. Inheriting `.btn`'s new `inline-flex / align-items: center / gap: 0.5rem` collided with the tile's internals and produced inconsistent letter sizing across project tiles. Set `display: inline-block` on `.btn-project` so the tile keeps its old block-level layout. The flex-related properties from `.btn` become inert once display is no longer flex. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/web/styles/project/_buttons.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/web/styles/project/_buttons.scss b/frontend/web/styles/project/_buttons.scss index f5e4b8b0a4b6..c65d61137ead 100644 --- a/frontend/web/styles/project/_buttons.scss +++ b/frontend/web/styles/project/_buttons.scss @@ -190,6 +190,9 @@ button.btn { } } &-project { + // Opt out of .btn's inline-flex/gap/44px-height — this is a tile-shaped + // surface, layout of letter+title is handled by the inner . + display: inline-block; background-color: $bg-light200; color: $body-color; padding: 0px 8px; From 3e775a2940b115b016c0b49c8919ace6750aac23 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 7 May 2026 16:32:58 -0300 Subject: [PATCH 10/13] refactor(invite-users): swap broken icon spacing for project Icon at 16px MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Invite additional member" button wrapped its icon+label in a `` with `pl-2 icon` on the icon span — that adds padding INSIDE the icon span (left of the icon), not between icon and text, so the icon and label touched each other. Drop the wrapper and pass the icon and text directly as Button children; `.btn`'s `gap: 0.5rem` now spaces them. Also swap the IonIcon `add` glyph for the project's `` to drop the third-party icon library on this consumer. Default plus icon size (21×20) is too heavy on a `size='small'` outline button — set `width={16}` to match the most common icon-in-small-button norm across the codebase (UserAction trash, PanelSearch refresh, etc.). Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/web/components/modals/InviteUsers.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/frontend/web/components/modals/InviteUsers.tsx b/frontend/web/components/modals/InviteUsers.tsx index 5f48e66113f3..4e46b7f7a063 100644 --- a/frontend/web/components/modals/InviteUsers.tsx +++ b/frontend/web/components/modals/InviteUsers.tsx @@ -3,7 +3,6 @@ import Button from 'components/base/forms/Button' import ConfigProvider from 'common/providers/ConfigProvider' import Constants from 'common/constants' import Icon from 'components/icons/Icon' -import { add } from 'ionicons/icons' import { IonIcon } from '@ionic/react' import { getPlanBasedOption } from 'components/PlanBasedAccess' import InputGroup from 'components/base/forms/InputGroup' @@ -282,14 +281,8 @@ const InviteUsers: FC = () => { ]) } > - - - - - - {isSaving ? 'Sending' : 'Invite additional member'} - - + + {isSaving ? 'Sending' : 'Invite additional member'} From 971afb1f04e36a525667c0d8d961a155854c46fd Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 7 May 2026 15:39:27 -0300 Subject: [PATCH 11/13] fix(view-docs): drop alignment hacks now that .btn is flex+gap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ViewDocs was working around `.btn`'s old inline-block layout with three hacks: `marginTop: -5` on the icon, `lineHeight: 24px` on a wrapper span, and a leading space inside the label string for spacing. With `.btn` now `inline-flex; align-items: center; gap: 0.5rem`, all three become unnecessary — the icon centres natively and gap handles the icon→label space. The hardcoded `fill='#6837fc'` stays for now (a dark-mode concern that belongs with the broader semantic-token migration). Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/web/components/ViewDocs.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/web/components/ViewDocs.tsx b/frontend/web/components/ViewDocs.tsx index 7936c7c2d6be..d84b5d21e672 100644 --- a/frontend/web/components/ViewDocs.tsx +++ b/frontend/web/components/ViewDocs.tsx @@ -7,8 +7,8 @@ type ViewDocsType = ButtonType & {} const ViewDocs: FC = (props) => { return ( ) } From 8f92fc8b4cd5f96a6a02b8aa5a88cfad67bf765a Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 7 May 2026 15:59:36 -0300 Subject: [PATCH 12/13] refactor(icons): swap hardcoded hex fills for semantic tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For files this PR has already touched, replace static hex fills on `` with their semantic token equivalents — or drop the fill prop entirely where the parent already sets the right colour and the icon defaults to `currentColor`: - ViewDocs: `#6837fc` → drop the prop. The icon now inherits via `currentColor` from `.btn-link`'s `$primary` colour. - InviteUsers invite-row trash: `#656D7B` → drop the prop. `.btn-with-icon` SCSS already sets `svg path { fill: var(--color-icon-secondary) }`, the explicit prop was redundant. The static hexes were invisible-or-wrong in dark mode (one of the findings in the design-system audit, #6606). The broader migration of the remaining ~85 hex-fill icons stays as a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/web/components/ViewDocs.tsx | 2 +- frontend/web/components/modals/InviteUsers.tsx | 2 +- frontend/web/components/pages/FlagEnvironmentsPage.tsx | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/web/components/ViewDocs.tsx b/frontend/web/components/ViewDocs.tsx index d84b5d21e672..ada7d4169e5c 100644 --- a/frontend/web/components/ViewDocs.tsx +++ b/frontend/web/components/ViewDocs.tsx @@ -7,7 +7,7 @@ type ViewDocsType = ButtonType & {} const ViewDocs: FC = (props) => { return ( ) diff --git a/frontend/web/components/modals/InviteUsers.tsx b/frontend/web/components/modals/InviteUsers.tsx index 4e46b7f7a063..214763ecb8fd 100644 --- a/frontend/web/components/modals/InviteUsers.tsx +++ b/frontend/web/components/modals/InviteUsers.tsx @@ -258,7 +258,7 @@ const InviteUsers: FC = () => { onClick={() => deleteInvite(invite.temporaryId)} className='btn btn-with-icon mb-2' > - + ) : ( diff --git a/frontend/web/components/pages/FlagEnvironmentsPage.tsx b/frontend/web/components/pages/FlagEnvironmentsPage.tsx index 01cdac090f39..53585d8f5d76 100644 --- a/frontend/web/components/pages/FlagEnvironmentsPage.tsx +++ b/frontend/web/components/pages/FlagEnvironmentsPage.tsx @@ -6,7 +6,7 @@ import { useGetEnvironmentsQuery } from 'common/services/useEnvironment' import { useGetFeatureStatesQuery } from 'common/services/useFeatureState' import { useGetProjectQuery } from 'common/services/useProject' import Panel from 'components/base/grid/Panel' -import { Icon } from 'components/icons' +import Icon from 'components/icons/Icon' import TagValues from 'components/tags/TagValues' import Switch from 'components/Switch' import Button from 'components/base/forms/Button' @@ -271,8 +271,7 @@ const FlagEnvironmentsPage: FC = () => { : '', }} > - From 1a0db6a3ef80018ef63da7a759b3cb4b6b58129c Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 7 May 2026 16:33:38 -0300 Subject: [PATCH 13/13] fix(buttons): make .btn-link inline-flex so theme='text' flows with text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the `.btn` switch to inline-flex, `theme='text'` buttons (which render as `.btn-link`) didn't behave as inline links anymore — they inherited the new 44px height pin and rendered as 44px boxes inline with surrounding text, throwing off any header that placed an Edit affordance next to a label (e.g. the alias row in the identity page). Make `.btn-link` properly inline-flow: - `display: inline-flex; align-items: center; gap: 0.25rem; vertical- align: baseline; height: auto` — the button hugs its content, centres icon+label internally, and aligns to the surrounding text baseline. Consumers no longer need `d-flex align-items-center` to centre a `theme='text'` button's children — the rule does that now. - Selector includes `button.btn-link` so `height: auto` beats `button.btn { height: 44px }`'s type-selector specificity for `