Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion frontend/.storybook/docs-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// =============================================================================

// Light mode — fix invisible inline code
.sbdocs code {
.sbdocs code:not(.hljs) {
color: #1a2634;
}

Expand Down Expand Up @@ -50,6 +50,15 @@
color: var(--color-text-default, #ffffff);
}

// Storybook marks rendered stories .sb-unstyled; the two rules above predate
// that and were repainting any <pre> a component renders. Skip .hljs, which
// brings its own surface.
.sbdocs .sb-unstyled code:not(.hljs),
.sbdocs .sb-unstyled pre:not(.hljs) {
background-color: transparent;
color: inherit;
}

// Storybook Source/code block container and all its children
.docblock-source,
.docblock-source > * {
Expand Down
33 changes: 33 additions & 0 deletions frontend/documentation/pages/DiffEnabled.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { Meta, StoryObj } from 'storybook'

import DiffEnabled from 'components/diff/DiffEnabled'

const meta: Meta<typeof DiffEnabled> = {
Comment thread
talissoncosta marked this conversation as resolved.
component: DiffEnabled,
parameters: {
docs: {
description: {
component:
'The diff view for a flag or segment override being turned on or off.',
},
},
layout: 'padded',
},
title: 'Components/Diff/DiffEnabled',
}

export default meta

type Story = StoryObj<typeof DiffEnabled>

export const OffToOn: Story = {
args: { newValue: true, oldValue: false },
}

export const OnToOff: Story = {
args: { newValue: false, oldValue: true },
}

export const Unchanged: Story = {
args: { newValue: true, oldValue: true },
}
51 changes: 51 additions & 0 deletions frontend/documentation/pages/DiffRow.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { Meta, StoryObj } from 'storybook'

import DiffRow from 'components/diff/DiffRow'

const meta: Meta<typeof DiffRow> = {
component: DiffRow,
parameters: {
docs: {
description: {
component:
'One row of a diff: a marker cell beside the content that changed. ' +
'Used by DiffEnabled and DiffString for the rows we build ourselves.',
},
},
layout: 'padded',
},
title: 'Components/Diff/DiffRow',
}

export default meta

type Story = StoryObj<typeof DiffRow>

export const Removed: Story = {
args: { children: 'banner_size: small', state: 'removed' },
}

export const Added: Story = {
args: { children: 'banner_size: large', state: 'added' },
}

export const Unchanged: Story = {
args: { children: 'banner_size: large', state: 'unchanged' },
}

export const Stacked: Story = {
render: () => (
<>
<DiffRow state='removed'>banner_size: small</DiffRow>
<DiffRow state='added'>banner_size: large</DiffRow>
</>
),
}

export const LongContentScrolls: Story = {
args: {
children: 'banner_size: '.repeat(40),
scrollable: true,
state: 'unchanged',
},
}
56 changes: 56 additions & 0 deletions frontend/documentation/pages/DiffString.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { Meta, StoryObj } from 'storybook'

import DiffString from 'components/diff/DiffString'

const meta: Meta<typeof DiffString> = {
component: DiffString,
parameters: {
docs: {
description: {
component:
'The diff view for flag values (react-diff-viewer + Prism for JSON). ' +
'Uses the same code colour tokens as the Highlight component, so it ' +
'follows light/dark mode. Toggle the theme in the toolbar to QA.',
},
},
layout: 'padded',
},
title: 'Components/Diff/DiffString',
}

export default meta

type Story = StoryObj<typeof DiffString>

const oldJson = `{
"id": "london-js",
"title": "Hello London.js!",
"description": "Join us at London.js and get insights on best practices!",
"buttonText": "Register on Meetup",
"isClosable": false
}`

const newJson = `{
"id": "london-js",
"title": "Hello London.js!",
"description": "Join us at London.js!",
"buttonText": "Register now",
"isClosable": true
}`

export const ChangedJson: Story = {
args: { newValue: newJson, oldValue: oldJson },
}

export const ChangedString: Story = {
args: { newValue: 'banner_size: large', oldValue: 'banner_size: small' },
}

export const SameJson: Story = {
args: { newValue: oldJson, oldValue: oldJson },
}

// An empty old value renders as `""`, not a blank row.
export const FromEmpty: Story = {
args: { newValue: 'banner_size: large', oldValue: '' },
}
24 changes: 7 additions & 17 deletions frontend/web/components/diff/DiffEnabled.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC } from 'react'
import classNames from 'classnames'
import Switch from 'components/Switch'
import DiffRow from './DiffRow'

type DiffType = {
oldValue: boolean
Expand All @@ -21,22 +21,12 @@ const DiffEnabled: FC<DiffType> = ({ newValue, oldValue }) => {
}
return (
<>
<div className={'flex-row'}>
<div className='react-diff-marker react-diff-marker--removed'>
<pre>-</pre>
</div>
<div className='react-diff-line react-diff-line--removed pe-2 flex-fill'>
<Switch checked={oldValue} />
</div>
</div>
<div className={'flex-row'}>
<div className='react-diff-marker react-diff-marker--added'>
<pre>+</pre>
</div>
<div className='react-diff-line react-diff-line--added pe-2 flex-fill'>
<Switch checked={newValue} />
</div>
</div>
<DiffRow state='removed'>
<Switch checked={oldValue} />
</DiffRow>
<DiffRow state='added'>
<Switch checked={newValue} />
</DiffRow>
</>
)
}
Expand Down
4 changes: 4 additions & 0 deletions frontend/web/components/diff/DiffFeature.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.diff-header {
font-size: 13px;
font-weight: 500;
}
9 changes: 5 additions & 4 deletions frontend/web/components/diff/DiffFeature.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import DiffFeatureStateValues from './DiffFeatureStateValues'
import DiffSegmentOverrides from './DiffSegmentOverrides'
import DiffVariations from './DiffVariations'
import './DiffFeature.scss'
import InfoMessage from 'components/InfoMessage'
import Icon from 'components/icons/Icon'
import WarningMessage from 'components/WarningMessage'
Expand Down Expand Up @@ -104,13 +105,13 @@ const DiffFeature: FC<FeatureDiffType> = ({
{(oldEnvName || newEnvName) && (
<div className='d-flex gap-3 mb-3'>
{oldEnvName && (
<span className='diff-removed-header'>
<span className='diff-sign'>−</span> {oldEnvName}
<span className='diff-header py-1 px-2 rounded-sm bg-surface-danger text-danger'>
<span className='me-1 fw-bold'>−</span> {oldEnvName}
</span>
)}
{newEnvName && (
<span className='diff-added-header'>
<span className='diff-sign'>+</span> {newEnvName}
<span className='diff-header py-1 px-2 rounded-sm bg-surface-success text-success'>
<span className='me-1 fw-bold'>+</span> {newEnvName}
</span>
)}
</div>
Expand Down
62 changes: 62 additions & 0 deletions frontend/web/components/diff/DiffRow/DiffRow.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// _react-diff.scss repeats these two values for the library's own rows.
.diff-row {
--diff-row-removed: oklch(from var(--red-500) l c h / 0.16);
--diff-row-added: oklch(from var(--green-500) l c h / 0.16);

line-height: 31px;

&__marker {
width: 31px;
height: 31px;
background-color: var(--color-surface-subtle);

> * {
margin: 0;
}
}

&__content {
flex: 1;
min-width: 0;
padding-right: 0.5rem;

.rc-switch {
margin-bottom: 2px;
}
}

&--removed {
.diff-row__marker,
.diff-row__content {
background-color: var(--diff-row-removed);
}
}

&--added {
.diff-row__marker,
.diff-row__content {
background-color: var(--diff-row-added);
}
}

&--unchanged {
background-color: var(--color-surface-subtle);
font-size: 13px;

.diff-row__marker {
opacity: 0;
}

.diff-row__content {
padding-right: 0;

pre {
padding-left: 2px;
background-color: var(--color-surface-subtle);
font-family: var(--bs-font-monospace);
font-size: 13px;
line-height: 28px;
}
}
}
}
42 changes: 42 additions & 0 deletions frontend/web/components/diff/DiffRow/DiffRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { FC, ReactNode } from 'react'
import classNames from 'classnames'
import './DiffRow.scss'

export type DiffRowState = 'added' | 'removed' | 'unchanged'

type DiffRowProps = {
state: DiffRowState
children: ReactNode
// Scroll long content rather than widening the container.
scrollable?: boolean
className?: string
}

const MARKERS: Record<DiffRowState, string> = {
added: '+',
removed: '-',
unchanged: '',
}

const DiffRow: FC<DiffRowProps> = ({
children,
className,
scrollable,
state,
}) => (
<div
className={classNames(
'diff-row d-flex align-items-center',
`diff-row--${state}`,
className,
{ 'overflow-auto': scrollable },
)}
>
<div className='diff-row__marker d-flex align-items-center justify-content-center flex-shrink-0'>
<pre>{MARKERS[state]}</pre>
</div>
<div className='diff-row__content'>{children}</div>
</div>
)

export default DiffRow
2 changes: 2 additions & 0 deletions frontend/web/components/diff/DiffRow/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './DiffRow'
export type { DiffRowState } from './DiffRow'
8 changes: 3 additions & 5 deletions frontend/web/components/diff/DiffString.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Diff, { DiffMethod } from 'react-diff-viewer-continued'
import Prism from 'prismjs'
import 'prismjs/components/prism-json'
import { FlagsmithValue } from 'common/types/responses'
import DiffRow from './DiffRow'

type DiffType = {
oldValue: FlagsmithValue
Expand Down Expand Up @@ -38,10 +39,7 @@ const DiffString: FC<DiffType> = ({
return <div className='text-muted'>No Value.</div>
}
return (
<div className='react-diff react-diff-same overflow-auto react-diff-line d-flex align-items-center'>
<span className='react-diff-marker'>
<pre></pre>
</span>
<DiffRow state='unchanged' scrollable>
<pre
className='d-inline mb-0'
dangerouslySetInnerHTML={{
Expand All @@ -52,7 +50,7 @@ const DiffString: FC<DiffType> = ({
),
}}
/>
</div>
</DiffRow>
)
}
return (
Expand Down
Loading
Loading