Skip to content

Commit

Permalink
Merge pull request #24099 from storybookjs/norbert/improve-status-ui-…
Browse files Browse the repository at this point in the history
…sidebar

UI: Improve look and feel of status UI in sidebar
(cherry picked from commit 9c49e16)
  • Loading branch information
ndelangen authored and storybook-bot committed Sep 15, 2023
1 parent fe2f0f4 commit 17f7b99
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 62 deletions.
5 changes: 3 additions & 2 deletions code/ui/components/src/components/tooltip/WithTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FC, ReactNode } from 'react';
import type { ComponentProps, FC, ReactNode } from 'react';
import React, { useCallback, useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import { styled } from '@storybook/theming';
Expand Down Expand Up @@ -28,6 +28,7 @@ interface WithHideFn {

export interface WithTooltipPureProps
extends Omit<ReactPopperTooltipConfig, 'closeOnOutsideClick'>,
Omit<ComponentProps<typeof TargetContainer>, 'trigger'>,
PopperOptions {
svg?: boolean;
withArrows?: boolean;
Expand Down Expand Up @@ -129,7 +130,7 @@ const WithTooltipPure: FC<WithTooltipPureProps> = ({

return (
<>
<Container trigger={trigger} ref={setTriggerRef as any} {...props}>
<Container trigger={trigger} ref={setTriggerRef as any} {...(props as any)}>
{children}
</Container>
{isVisible && ReactDOM.createPortal(tooltipComponent, document.body)}
Expand Down
6 changes: 2 additions & 4 deletions code/ui/manager/src/components/sidebar/SearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,12 @@ const Result: FC<
node = <DocumentNode href={getLink(item, item.refId)} {...nodeProps} />;
}

const [i, iconColor] = item.status ? statusMapping[item.status] : [];
const [i] = item.status ? statusMapping[item.status] : [];

return (
<ResultRow {...props}>
{node}
{item.status ? (
<Icons width="8px" height="8px" icon={i} style={{ color: iconColor }} />
) : null}
{item.status ? i : null}
</ResultRow>
);
});
Expand Down
89 changes: 44 additions & 45 deletions code/ui/manager/src/components/sidebar/Tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,44 +37,47 @@ import {
} from '../../utils/tree';
import { statusMapping, getHighestStatus, getGroupStatus } from '../../utils/status';

export const Action = styled.button(({ theme }) => ({
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: 20,
height: 20,
margin: 0,
marginLeft: 'auto',
padding: 0,
outline: 0,
lineHeight: 'normal',
background: 'none',
border: `1px solid transparent`,
borderRadius: '100%',
cursor: 'pointer',
transition: 'all 150ms ease-out',
color:
theme.base === 'light'
? transparentize(0.3, theme.color.defaultText)
: transparentize(0.6, theme.color.defaultText),

'&:hover': {
color: theme.color.secondary,
},
'&:focus': {
color: theme.color.secondary,
borderColor: theme.color.secondary,
export const Action = styled.button<{ height?: number; width?: number }>(
({ theme, height, width }) => ({
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: width || 20,
height: height || 20,
boxSizing: 'border-box',
margin: 0,
marginLeft: 'auto',
padding: 0,
outline: 0,
lineHeight: 'normal',
background: 'none',
border: `1px solid transparent`,
borderRadius: '100%',
cursor: 'pointer',
transition: 'all 150ms ease-out',
color:
theme.base === 'light'
? transparentize(0.3, theme.color.defaultText)
: transparentize(0.6, theme.color.defaultText),

'&:hover': {
color: theme.color.secondary,
},
'&:focus': {
color: theme.color.secondary,
borderColor: theme.color.secondary,

'&:not(:focus-visible)': {
borderColor: 'transparent',
'&:not(:focus-visible)': {
borderColor: 'transparent',
},
},
},

svg: {
width: 10,
height: 10,
},
}));
svg: {
width: 10,
height: 10,
},
})
);

const CollapseButton = styled.button(({ theme }) => ({
// Reset button
Expand Down Expand Up @@ -207,7 +210,7 @@ const Node = React.memo<NodeProps>(function Node({
const LeafNode = item.type === 'docs' ? DocumentNode : StoryNode;

const statusValue = getHighestStatus(Object.values(status || {}).map((s) => s.status));
const [icon, iconColor, textColor] = statusMapping[statusValue];
const [icon, textColor] = statusMapping[statusValue];

return (
<LeafNodeStyleWrapper
Expand Down Expand Up @@ -241,25 +244,21 @@ const Node = React.memo<NodeProps>(function Node({
{icon ? (
<WithTooltip
placement="top"
style={{ display: 'flex' }}
tooltip={() => (
<TooltipLinkList
links={Object.entries(status || {}).map(([k, v]) => ({
id: k,
title: v.title,
description: v.description,
right: (
<Icons
icon={statusMapping[v.status][0]}
style={{ color: statusMapping[v.status][1] }}
/>
),
right: statusMapping[v.status][0],
}))}
/>
)}
closeOnOutsideClick
>
<Action type="button">
<Icons icon={icon} style={{ color: isSelected ? 'white' : iconColor }} />
<Action type="button" height={22}>
{icon}
</Action>
</WithTooltip>
) : null}
Expand Down Expand Up @@ -530,7 +529,7 @@ export const Tree = React.memo<{
}

const isDisplayed = !item.parent || ancestry[itemId].every((a: string) => expanded[a]);
const color = groupStatus[itemId] ? statusMapping[groupStatus[itemId]][2] : null;
const color = groupStatus[itemId] ? statusMapping[groupStatus[itemId]][1] : null;

return (
<Node
Expand Down
36 changes: 25 additions & 11 deletions code/ui/manager/src/utils/status.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import type { Icons } from '@storybook/components';
import type { ComponentProps } from 'react';
import React from 'react';
import { Icons } from '@storybook/components';
import type { ReactElement } from 'react';
import type { API_HashEntry, API_StatusState, API_StatusValue } from '@storybook/types';

import { styled } from '@storybook/theming';
// eslint-disable-next-line import/no-cycle
import { getDescendantIds } from './tree';

const SmallIcons = styled(Icons)({
// specificity hack
'&&&': {
width: 6,
height: 6,
},
});

const LoadingIcons = styled(SmallIcons)(({ theme: { animation, color, base } }) => ({
// specificity hack
animation: `${animation.glow} 1.5s ease-in-out infinite`,
color: base === 'light' ? color.mediumdark : color.darker,
}));

export const statusPriority: API_StatusValue[] = ['unknown', 'pending', 'success', 'warn', 'error'];
export const statusMapping: Record<
API_StatusValue,
[ComponentProps<typeof Icons>['icon'] | null, string | null, string | null]
> = {
unknown: [null, null, null],
pending: ['watch', 'currentColor', 'currentColor'],
success: ['circle', 'green', 'currentColor'],
warn: ['circle', 'orange', '#A15C20'],
error: ['circle', 'red', 'brown'],
export const statusMapping: Record<API_StatusValue, [ReactElement | null, string | null]> = {
unknown: [null, null],
pending: [<LoadingIcons key="icon" icon="circle" />, 'currentColor'],
success: [<SmallIcons key="icon" icon="circle" style={{ color: 'green' }} />, 'currentColor'],
warn: [<SmallIcons key="icon" icon="circle" style={{ color: 'orange' }} />, '#A15C20'],
error: [<SmallIcons key="icon" icon="circle" style={{ color: 'red' }} />, 'brown'],
};

export const getHighestStatus = (statuses: API_StatusValue[]): API_StatusValue => {
Expand Down

0 comments on commit 17f7b99

Please sign in to comment.