Skip to content

Commit

Permalink
chore: improve storybook icon tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
amje committed Jan 6, 2023
1 parent c44a536 commit 0bf3935
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 18 deletions.
21 changes: 21 additions & 0 deletions .storybook/src/IconTooltip/IconTooltip.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@use '~@gravity-ui/uikit/styles/mixins';

.icon-tooltip {
--yc-popover-max-width: 1000px;

&__grid {
display: grid;
grid-template-columns: max-content minmax(max-content, 1fr);
gap: 12px;
}

&__label {
@include mixins.text-accent;
}

&__value {
white-space: nowrap;
font-family: 'SF Mono', 'Menlo', 'Monaco', 'Consolas', 'Ubuntu Mono', 'Liberation Mono',
'DejaVu Sans Mono', 'Courier New', 'Courier', monospace;
}
}
73 changes: 73 additions & 0 deletions .storybook/src/IconTooltip/IconTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import block from 'bem-cn-lite';
import {Popover, PopoverInstanceProps, Label} from '@gravity-ui/uikit';

import './IconTooltip.scss';

export interface IconTooltipProps {
componentName: string;
svgPath: string;
importLine: string;
children: React.ReactElement;
forceOpen?: boolean;
}

const b = block('icon-tooltip');

export function IconTooltip({
componentName,
svgPath,
importLine,
forceOpen,
children,
}: IconTooltipProps) {
const popoverRef = React.useRef<PopoverInstanceProps>();
const content = React.useMemo(
() => (
<div className={b('grid')}>
<div className={b('label')}>Name</div>
<div className={b('value')}>
<Label type="copy" copyText={componentName}>
{componentName}
</Label>
</div>
<div className={b('label')}>Path</div>
<div className={b('value')}>
<Label type="copy" copyText={svgPath}>
{svgPath}
</Label>
</div>
<div className={b('label')}>Import</div>
<div className={b('value')}>
<Label type="copy" copyText={importLine}>
{importLine}
</Label>
</div>
</div>
),
[],
);

React.useEffect(() => {
if (!popoverRef.current) {
return;
}

if (forceOpen) {
popoverRef.current.openTooltip();
} else {
popoverRef.current?.closeTooltip();
}
}, [forceOpen]);

return (
<Popover
ref={popoverRef}
content={content}
placement={['bottom', 'top']}
tooltipClassName={b()}
>
{children}
</Popover>
);
}
48 changes: 33 additions & 15 deletions .storybook/src/Showcase.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react';
import block from 'bem-cn-lite';
import {Meta, Story} from '@storybook/react';
import {Button, Icon as IconWrapper, Tooltip} from '@gravity-ui/uikit';
import {Button, Icon as IconWrapper} from '@gravity-ui/uikit';
import {IconTooltip} from './IconTooltip/IconTooltip';
import metadata from '../../metadata.json';

import './Showcase.stories.scss';
Expand All @@ -18,6 +20,7 @@ interface IconMeta {
aliases: string[];
}

const b = block('showcase');
const libContext = require.context('../../lib', false, /\.tsx$/);
const iconsMetadataByName = (metadata.icons as IconMeta[]).reduce(
(acc, icon) => ({...acc, [icon.componentName]: icon}),
Expand All @@ -30,9 +33,10 @@ export const Showcase: Story = () => {
const module = libContext(path);
const Icon = module.default || module;
const name = path.match(/(\w+)\.tsx$/)?.[1] ?? '';
const meta = iconsMetadataByName[name];

return {
name,
meta,
Icon,
};
});
Expand All @@ -42,42 +46,56 @@ export const Showcase: Story = () => {
if (search.length === 0) {
filteredItems = items;
} else {
filteredItems = items.filter(({name}) => {
const meta = iconsMetadataByName[name];

const searchLower = search.toLowerCase();
filteredItems = items.filter(({meta}) => {
return (
meta.name.includes(search) ||
meta.aliases.some((alias: string) => alias.includes(search))
meta.name.toLowerCase().includes(searchLower) ||
meta.componentName.toLowerCase().includes(searchLower) ||
meta.aliases.some((alias: string) => alias.toLowerCase().includes(searchLower))
);
});
}

return (
<div className="showcase">
<div className="showcase__search">
<div className={b()}>
<div className={b('search')}>
<input
type="text"
placeholder="Search"
autoFocus
className="showcase__search-input"
className={b('search-input')}
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</div>
<div className="showcase__items">
<div className={b('items')}>
{filteredItems.length > 0 ? (
filteredItems.map(({name, Icon}) => (
<Tooltip key={name} content={name} openDelay={250}>
filteredItems.map(({meta, Icon}) => (
<IconTooltip
key={meta.svgName}
componentName={meta.componentName}
svgPath={buildIconSvgPath(meta.svgName)}
importLine={buildIconImportLine(meta.componentName)}
forceOpen={filteredItems.length === 1}
>
<Button view="flat" size="xl">
<IconWrapper data={Icon} size={24} />
</Button>
</Tooltip>
</IconTooltip>
))
) : (
<div className="showcase__empty">Nothing found :(</div>
<div className={b('empty')}>Nothing found :(</div>
)}
</div>
</div>
);
};
Showcase.storyName = 'Showcase';

function buildIconSvgPath(svgName: string) {
return `@gravity-ui/icons/svgs/${svgName}.svg`;
}

function buildIconImportLine(componentName: string) {
return `import {${componentName}} from '@gravity-ui/icons';`;
}
15 changes: 12 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@svgr/core": "^6.5.1",
"@types/react": "^17.0.52",
"@types/react-dom": "^17.0.18",
"bem-cn-lite": "^4.1.0",
"cross-env": "^7.0.3",
"css-loader": "^5.2.7",
"eslint": "^8.29.0",
Expand Down

0 comments on commit 0bf3935

Please sign in to comment.