From cacd824f2b145c370e50e24f8a95a4621bbd1f99 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 8 Jul 2026 16:15:44 -0300 Subject: [PATCH 1/6] refactor(styles): theme-adaptive shared code theme (.hljs) [spike #6606] Convert the shared highlight.js theme from its hardcoded dark palette to semantic tokens, so code blocks adapt to light/dark instead of always rendering dark. Code surface -> --color-surface-subtle; syntax colours -> the --color-text-* palette (first pass, lifted from the onboarding code card). Spike: .hljs is shared app-wide incl. the interactive value editor, so this is a visible change everywhere. Opened to see the real diff via CI visual regression before committing to a designed palette. Refs #6606 Co-Authored-By: Claude Opus 4.8 --- frontend/web/styles/3rdParty/_hljs.scss | 34 +++++++++++++------------ 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/frontend/web/styles/3rdParty/_hljs.scss b/frontend/web/styles/3rdParty/_hljs.scss index 2b564e813435..8486d9892bb9 100644 --- a/frontend/web/styles/3rdParty/_hljs.scss +++ b/frontend/web/styles/3rdParty/_hljs.scss @@ -69,11 +69,11 @@ } .hljs { a { - color: white !important; + color: var(--color-text-action) !important; text-decoration: underline; .hljs-regexp, .hljs-comment { - color: white !important; + color: var(--color-text-action) !important; } } cursor: text; @@ -83,9 +83,11 @@ overflow-x: auto; @include customScrollDark(); padding: 0.5em; - background: $code-bg; + // #6606 spike: theme-adaptive code surface (light in light mode, dark in + // dark) via semantic tokens, replacing the hardcoded dark $code-bg. + background: var(--color-surface-subtle); border-radius: $border-radius; - border: 1px solid $basic-alpha-8; + border: 1px solid var(--color-border-default); &.no-pad { margin-bottom: 0; } @@ -99,13 +101,13 @@ } .yaml { .hljs-bullet { - color: #eee; + color: var(--color-text-default); } .hljs-attr { - color: #64c77c; + color: var(--color-text-success); } .hljs-string { - color: #4c96ec; + color: var(--color-text-info); } } .hljs-container { @@ -177,7 +179,7 @@ } .hljs { - color: $code-color; + color: var(--color-text-default); padding: 18px; } @@ -186,7 +188,7 @@ } .hljs-strong, .hljs-emphasis { - color: #a8a8a2; + color: var(--color-text-secondary); } .hljs-bullet, @@ -195,12 +197,12 @@ .hljs-number, .hljs-regexp, .hljs-literal { - color: $info; + color: var(--color-text-info); } .hljs-code, .hljs-selector-class { - color: #a6e22e; + color: var(--color-text-success); } .hljs-emphasis { @@ -213,15 +215,15 @@ .hljs-attribute, .hljs-name, .hljs-variable { - color: $warning; + color: var(--color-text-action); } .hljs-params { - color: #b9b9b9; + color: var(--color-text-secondary); } .hljs-string { - color: $success; + color: var(--color-text-success); } .hljs-subst, @@ -235,13 +237,13 @@ .hljs-template-tag, .hljs-template-variable, .hljs-addition { - color: $secondary400; + color: var(--color-text-info); } .hljs-comment, .hljs-deletion, .hljs-meta { - color: #7f7f7f; + color: var(--color-text-secondary); } .value-editor pre { overflow: hidden; From 678bcf18f0b2af73aa4d4b245aa947e3efb2672f Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 8 Jul 2026 16:45:21 -0300 Subject: [PATCH 2/6] refactor(styles): drop two redundant !important in the code theme Both were already won by the cascade: .select-language span.primary follows .active at equal specificity, and code[contenteditable].hljs outranks .hljs. The remaining !important beat highlight.js's own CSS / the Button / global resets. Refs #6606 Co-Authored-By: Claude Opus 4.8 --- frontend/web/styles/3rdParty/_hljs.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/web/styles/3rdParty/_hljs.scss b/frontend/web/styles/3rdParty/_hljs.scss index 8486d9892bb9..6c3e64213b81 100644 --- a/frontend/web/styles/3rdParty/_hljs.scss +++ b/frontend/web/styles/3rdParty/_hljs.scss @@ -62,7 +62,7 @@ font-weight: 500; } &.primary { - color: $primary !important; + color: $primary; } } } @@ -298,6 +298,6 @@ code.txt { } code[contenteditable='false'].hljs { - cursor: default !important; + cursor: default; @include customScrollDark(); } From 44a3541b96bde9e9f7630971130003f2b812c58a Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Wed, 8 Jul 2026 16:49:33 -0300 Subject: [PATCH 3/6] docs(storybook): CodeHelp stories covering the app's use cases Render CodeHelp with the real codeHelp snippets (install, init, create identity, set traits) plus collapsed-header and embedded variants, so the shared code block can be QA'd in light and dark (theme toggle) and across languages (dropdown) in one place - the safety net for the #6606 theme change. Registers window.Button in the Storybook preview, since CodeHelp uses the global Button like Select. Refs #6606 Co-Authored-By: Claude Opus 4.8 --- frontend/.storybook/preview.js | 2 + .../documentation/pages/CodeHelp.stories.tsx | 77 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 frontend/documentation/pages/CodeHelp.stories.tsx diff --git a/frontend/.storybook/preview.js b/frontend/.storybook/preview.js index 54f8d7f7c031..9925a79b1969 100644 --- a/frontend/.storybook/preview.js +++ b/frontend/.storybook/preview.js @@ -17,6 +17,7 @@ import ReactSelect, { components as selectComponents } from 'react-select' import Tooltip from '../web/components/Tooltip' import Row from '../web/components/base/grid/Row' import FormGroup from '../web/components/base/grid/FormGroup' +import Button from '../web/components/base/forms/Button' window.React = React window.propTypes = PropTypes @@ -55,6 +56,7 @@ global.Select = (props) => window.Tooltip = Tooltip window.Row = Row window.FormGroup = FormGroup +window.Button = Button /** @type { import('storybook').Preview } */ const preview = { diff --git a/frontend/documentation/pages/CodeHelp.stories.tsx b/frontend/documentation/pages/CodeHelp.stories.tsx new file mode 100644 index 000000000000..1cb58d0e31fd --- /dev/null +++ b/frontend/documentation/pages/CodeHelp.stories.tsx @@ -0,0 +1,77 @@ +import type { Meta, StoryObj } from 'storybook' + +import CodeHelp from 'components/CodeHelp' +import Constants from 'common/constants' + +// A stand-in environment key for the snippets. +const ENV = 'YOUR_ENVIRONMENT_KEY' + +const meta: Meta = { + component: CodeHelp, + parameters: { + docs: { + description: { + component: + 'The shared code-example component, used across SDK setup, identities, segments and environment docs. These stories mirror those real use cases with the actual `codeHelp` snippets. Use the theme toggle in the toolbar to QA the code block (surface + syntax colours) in light and dark, and the language dropdown to check each SDK.', + }, + }, + layout: 'padded', + }, + title: 'Components/CodeHelp', +} +export default meta + +type Story = StoryObj + +// Installing the SDK (SDK integration page). +export const Install: Story = { + args: { + showInitially: true, + snippets: Constants.codeHelp.INSTALL, + title: 'Installing the SDK', + }, +} + +// Initialising the client, keyed by the environment (the most common use). +export const Initialise: Story = { + args: { + showInitially: true, + snippets: Constants.codeHelp.INIT(ENV), + title: 'Initialising your project', + }, +} + +// Creating an identity (identities pages). +export const CreateIdentity: Story = { + args: { + showInitially: true, + snippets: Constants.codeHelp.CREATE_USER(ENV), + title: 'Creating an identity', + }, +} + +// Setting traits (identities pages). +export const SetTraits: Story = { + args: { + showInitially: true, + snippets: Constants.codeHelp.USER_TRAITS(ENV), + title: 'Setting traits', + }, +} + +// Default entry point: the collapsed CalloutBar header before it's opened. +export const CollapsedHeader: Story = { + args: { + snippets: Constants.codeHelp.INSTALL, + title: 'Installing the SDK', + }, +} + +// Embedded with no header and no docs links (e.g. inside another panel). +export const Embedded: Story = { + args: { + hideDocs: true, + hideHeader: true, + snippets: Constants.codeHelp.INIT(ENV), + }, +} From 45e6b143209c24d33ec96d139d04193679e3cb05 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 9 Jul 2026 11:35:10 -0300 Subject: [PATCH 4/6] refactor(styles): make onboarding's code treatment the shared standard Adopt the onboarding code card's restrained palette (five semantic-token groups, unmapped tokens inherit the base) as the shared `.hljs` theme, and add a `.hljs--embedded` modifier for code that sits in a container already providing the surface (transparent, no border/radius, gutter-reserved scrollbar). Onboarding's bespoke .hljs block collapses to that one class. Refs #6606 Co-Authored-By: Claude Opus 4.8 --- .../OnboardingConnectPanel/CodeCard.tsx | 2 +- .../OnboardingConnectPanel.scss | 62 +------------ frontend/web/styles/3rdParty/_hljs.scss | 89 ++++++++++--------- 3 files changed, 50 insertions(+), 103 deletions(-) diff --git a/frontend/web/components/pages/onboarding/OnboardingConnectPanel/CodeCard.tsx b/frontend/web/components/pages/onboarding/OnboardingConnectPanel/CodeCard.tsx index 270897ec8742..c337467bf4d8 100644 --- a/frontend/web/components/pages/onboarding/OnboardingConnectPanel/CodeCard.tsx +++ b/frontend/web/components/pages/onboarding/OnboardingConnectPanel/CodeCard.tsx @@ -47,7 +47,7 @@ const CodeCard: FC = ({ - + {code} diff --git a/frontend/web/components/pages/onboarding/OnboardingConnectPanel/OnboardingConnectPanel.scss b/frontend/web/components/pages/onboarding/OnboardingConnectPanel/OnboardingConnectPanel.scss index 55e5df84ecd0..04a423a772eb 100644 --- a/frontend/web/components/pages/onboarding/OnboardingConnectPanel/OnboardingConnectPanel.scss +++ b/frontend/web/components/pages/onboarding/OnboardingConnectPanel/OnboardingConnectPanel.scss @@ -32,67 +32,13 @@ } } - // Code cards - theme-adaptive via semantic tokens (light editor in light mode, - // dark in dark mode). Surface, base text and every syntax colour map to - // semantic tokens that flip with the theme, so there's no hardcoded hex and no - // per-theme override. TODO(#6606): lift this palette into the shared `.hljs` - // theme so all code blocks app-wide adapt the same way. + // The code card owns the surface and rounding; the code block inside opts + // into the shared `.hljs--embedded` modifier (transparent, no border/radius, + // gutter-reserved scrollbar). Palette and theme adaptation now come from the + // shared `.hljs` theme (#6606) - no per-card overrides. &__codecard { border-radius: 10px; overflow: hidden; - - .hljs { - // Inherit the card surface; base text adapts with the theme. - background: transparent; - border: 0; - border-radius: 0; - color: var(--color-text-default); - // Reserve the scrollbar gutter permanently so hover doesn't shove the - // layout (the global dark-scroll mixin toggles display:none on a - // space-reserving webkit bar otherwise). - overflow-x: scroll; - overflow-y: hidden; - - &::-webkit-scrollbar, - &:hover::-webkit-scrollbar { - display: block !important; - } - - // Unmapped tokens (tags, attributes, params, punctuation) inherit the - // readable base instead of the global hljs greys; the semantic palette - // below re-colours the specific token types. - * { - color: inherit; - } - } - - .hljs-keyword, - .hljs-built_in, - .hljs-literal, - .hljs-selector-tag { - color: var(--color-text-action); - } - .hljs-string, - .hljs-regexp { - color: var(--color-text-success); - } - .hljs-attr, - .hljs-attribute, - .hljs-property, - .hljs-number, - .hljs-type { - color: var(--color-text-info); - } - .hljs-title, - .hljs-name, - .hljs-section { - color: var(--color-text-default); - } - .hljs-comment, - .hljs-quote, - .hljs-meta { - color: var(--color-text-secondary); - } } &__codecard-head { diff --git a/frontend/web/styles/3rdParty/_hljs.scss b/frontend/web/styles/3rdParty/_hljs.scss index 6c3e64213b81..c944384bda17 100644 --- a/frontend/web/styles/3rdParty/_hljs.scss +++ b/frontend/web/styles/3rdParty/_hljs.scss @@ -181,70 +181,52 @@ .hljs { color: var(--color-text-default); padding: 18px; + // Unmapped tokens fall back to the readable base colour instead of the + // highlight.js greys; the semantic palette below re-colours specific types. + // Kept intentionally restrained (five groups) - this is the palette lifted + // from the onboarding code card, now the shared standard (#6606). + * { + color: inherit; + } } .json { border: none; } -.hljs-strong, -.hljs-emphasis { - color: var(--color-text-secondary); -} - -.hljs-bullet, -.hljs-quote, -.hljs-link, -.hljs-number, -.hljs-regexp, -.hljs-literal { - color: var(--color-text-info); -} - -.hljs-code, -.hljs-selector-class { - color: var(--color-text-success); -} - -.hljs-emphasis { - font-style: italic; -} .hljs-keyword, -.hljs-selector-tag, -.hljs-section, -.hljs-attribute, -.hljs-name, -.hljs-variable { +.hljs-built_in, +.hljs-literal, +.hljs-selector-tag { color: var(--color-text-action); } -.hljs-params { - color: var(--color-text-secondary); -} - -.hljs-string { +.hljs-string, +.hljs-regexp { color: var(--color-text-success); } -.hljs-subst, -.hljs-type, -.hljs-built_in, -.hljs-builtin-name, -.hljs-symbol, -.hljs-selector-id, -.hljs-selector-attr, -.hljs-selector-pseudo, -.hljs-template-tag, -.hljs-template-variable, -.hljs-addition { +.hljs-attr, +.hljs-attribute, +.hljs-property, +.hljs-number, +.hljs-type { color: var(--color-text-info); } .hljs-comment, -.hljs-deletion, +.hljs-quote, .hljs-meta { color: var(--color-text-secondary); } + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} .value-editor pre { overflow: hidden; } @@ -301,3 +283,22 @@ code[contenteditable='false'].hljs { cursor: default; @include customScrollDark(); } + +// Code that sits inside a container which already provides the surface (e.g. +// the onboarding code card). The container owns the background, border and +// rounding; the code block itself is transparent and only scrolls sideways. +.hljs--embedded { + background: transparent; + border: 0; + border-radius: 0; + // Reserve the horizontal scrollbar gutter so hovering doesn't shift the + // layout - the default dark-scroll bar toggles display and reflows. The + // !important beats customScrollDark's display:none on non-editable code. + overflow-x: scroll; + overflow-y: hidden; + + &::-webkit-scrollbar, + &:hover::-webkit-scrollbar { + display: block !important; + } +} From 26f3c5a1f6b5f133951ed8654afce329017f0c25 Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Thu, 9 Jul 2026 11:35:20 -0300 Subject: [PATCH 5/6] refactor(components): import Button in CodeHelp/Highlight instead of the global Both reached for a bare `window.Button` (the legacy project-components.js pattern) rather than importing it, which meant Storybook had to fake the global. Import Button directly so they stand alone, and drop the shim from the Storybook preview. Also de-nests Highlight's pre-existing html ternary into a small helper so the touched file passes lint. Refs #6606 Co-Authored-By: Claude Opus 4.8 --- frontend/.storybook/preview.js | 2 -- frontend/web/components/CodeHelp.tsx | 1 + frontend/web/components/Highlight.js | 36 ++++++++++------------------ 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/frontend/.storybook/preview.js b/frontend/.storybook/preview.js index 9925a79b1969..54f8d7f7c031 100644 --- a/frontend/.storybook/preview.js +++ b/frontend/.storybook/preview.js @@ -17,7 +17,6 @@ import ReactSelect, { components as selectComponents } from 'react-select' import Tooltip from '../web/components/Tooltip' import Row from '../web/components/base/grid/Row' import FormGroup from '../web/components/base/grid/FormGroup' -import Button from '../web/components/base/forms/Button' window.React = React window.propTypes = PropTypes @@ -56,7 +55,6 @@ global.Select = (props) => window.Tooltip = Tooltip window.Row = Row window.FormGroup = FormGroup -window.Button = Button /** @type { import('storybook').Preview } */ const preview = { diff --git a/frontend/web/components/CodeHelp.tsx b/frontend/web/components/CodeHelp.tsx index ad2dbb87e052..500a30beb4ee 100644 --- a/frontend/web/components/CodeHelp.tsx +++ b/frontend/web/components/CodeHelp.tsx @@ -5,6 +5,7 @@ import Constants from 'common/constants' import Utils from 'common/utils/utils' import Icon from './icons/Icon' import CalloutBar from './CalloutBar' +import Button from './base/forms/Button' type Snippets = Record diff --git a/frontend/web/components/Highlight.js b/frontend/web/components/Highlight.js index 6f5ae59ccaf4..0cf70993d8c1 100644 --- a/frontend/web/components/Highlight.js +++ b/frontend/web/components/Highlight.js @@ -1,5 +1,6 @@ import React from 'react' import hljs from 'highlight.js' +import Button from './base/forms/Button' function escapeHtml(unsafe) { if (!unsafe || !unsafe.__html) return unsafe @@ -103,14 +104,16 @@ class Highlight extends React.Component { this.props.onBlur?.() } + // The value to render before escaping: the live edit while focused, the + // current value when there's content, otherwise a disabled/empty placeholder. + getRawHtml = () => { + if (this.state.focus) return this.state.value + if (this.props.children) return { ...this.state.value } + return this.props.disabled ? defaultDisabledValue : defaultValue + } + render() { - const { - children, - className, - disabled, - element: Element, - innerHTML, - } = this.props + const { children, className, element: Element, innerHTML } = this.props const props = { className, ref: this.setEl } if (innerHTML) { @@ -125,23 +128,8 @@ class Highlight extends React.Component { return {children} } - const html = this.props.preventEscape - ? this.state.focus - ? this.state.value - : this.props.children - ? { ...this.state.value } - : disabled - ? defaultDisabledValue - : defaultValue - : escapeHtml( - this.state.focus - ? this.state.value - : this.props.children - ? { ...this.state.value } - : disabled - ? defaultDisabledValue - : defaultValue, - ) + const raw = this.getRawHtml() + const html = this.props.preventEscape ? raw : escapeHtml(raw) return (
Date: Wed, 15 Jul 2026 15:03:41 -0300
Subject: [PATCH 6/6] docs(styles): trim code-theme comments, drop issue refs

Co-Authored-By: Claude Opus 4.8 
---
 .../OnboardingConnectPanel.scss               |  6 ++----
 frontend/web/styles/3rdParty/_hljs.scss       | 19 +++++++------------
 2 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/frontend/web/components/pages/onboarding/OnboardingConnectPanel/OnboardingConnectPanel.scss b/frontend/web/components/pages/onboarding/OnboardingConnectPanel/OnboardingConnectPanel.scss
index 04a423a772eb..08511e85cb02 100644
--- a/frontend/web/components/pages/onboarding/OnboardingConnectPanel/OnboardingConnectPanel.scss
+++ b/frontend/web/components/pages/onboarding/OnboardingConnectPanel/OnboardingConnectPanel.scss
@@ -32,10 +32,8 @@
     }
   }
 
-  // The code card owns the surface and rounding; the code block inside opts
-  // into the shared `.hljs--embedded` modifier (transparent, no border/radius,
-  // gutter-reserved scrollbar). Palette and theme adaptation now come from the
-  // shared `.hljs` theme (#6606) - no per-card overrides.
+  // The card owns the surface + rounding; the code block opts into the shared
+  // `.hljs--embedded` modifier for its palette and theme adaptation.
   &__codecard {
     border-radius: 10px;
     overflow: hidden;
diff --git a/frontend/web/styles/3rdParty/_hljs.scss b/frontend/web/styles/3rdParty/_hljs.scss
index c944384bda17..f1af897834aa 100644
--- a/frontend/web/styles/3rdParty/_hljs.scss
+++ b/frontend/web/styles/3rdParty/_hljs.scss
@@ -83,8 +83,7 @@
   overflow-x: auto;
   @include customScrollDark();
   padding: 0.5em;
-  // #6606 spike: theme-adaptive code surface (light in light mode, dark in
-  // dark) via semantic tokens, replacing the hardcoded dark $code-bg.
+  // Theme-adaptive surface: light in light mode, dark in dark, via tokens.
   background: var(--color-surface-subtle);
   border-radius: $border-radius;
   border: 1px solid var(--color-border-default);
@@ -181,10 +180,8 @@
 .hljs {
   color: var(--color-text-default);
   padding: 18px;
-  // Unmapped tokens fall back to the readable base colour instead of the
-  // highlight.js greys; the semantic palette below re-colours specific types.
-  // Kept intentionally restrained (five groups) - this is the palette lifted
-  // from the onboarding code card, now the shared standard (#6606).
+  // Unmapped tokens inherit the base colour instead of the highlight.js greys;
+  // the palette below re-colours specific types.
   * {
     color: inherit;
   }
@@ -284,16 +281,14 @@ code[contenteditable='false'].hljs {
   @include customScrollDark();
 }
 
-// Code that sits inside a container which already provides the surface (e.g.
-// the onboarding code card). The container owns the background, border and
-// rounding; the code block itself is transparent and only scrolls sideways.
+// For code inside a container that already provides the surface: transparent,
+// no border/radius; the container owns the frame.
 .hljs--embedded {
   background: transparent;
   border: 0;
   border-radius: 0;
-  // Reserve the horizontal scrollbar gutter so hovering doesn't shift the
-  // layout - the default dark-scroll bar toggles display and reflows. The
-  // !important beats customScrollDark's display:none on non-editable code.
+  // Reserve the scrollbar gutter so hover doesn't shift layout; !important
+  // beats customScrollDark's display:none on non-editable code.
   overflow-x: scroll;
   overflow-y: hidden;