feat(graph): update tags to render on a single line by default with expand option (#27829)

This commit is contained in:
MaxKless 2024-09-09 18:07:24 +03:00 committed by GitHub
parent d72a1d4e6e
commit b8486fb53f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 125 additions and 12 deletions

View File

@ -6,11 +6,11 @@ import { GraphError } from 'nx/src/command-line/graph/graph';
/* eslint-enable @nx/enforce-module-boundaries */
import { EyeIcon } from '@heroicons/react/24/outline';
import { PropertyInfoTooltip, Tooltip } from '@nx/graph/ui-tooltips';
import { TooltipTriggerText } from '../target-configuration-details/tooltip-trigger-text';
import { twMerge } from 'tailwind-merge';
import { Pill } from '../pill';
import { TargetTechnologies } from '../target-technologies/target-technologies';
import { TagList } from '../tag-list/tag-list';
import { TargetConfigurationGroupList } from '../target-configuration-details-group-list/target-configuration-details-group-list';
import { TooltipTriggerText } from '../target-configuration-details/tooltip-trigger-text';
import { TargetTechnologies } from '../target-technologies/target-technologies';
export interface ProjectDetailsProps {
project: ProjectGraphProjectNode;
@ -97,21 +97,14 @@ export const ProjectDetails = ({
)}
</div>
<div className="flex flex-wrap justify-between py-2">
<div>
<div className="min-w-0">
{projectData.metadata?.description ? (
<p className="mb-2 text-sm capitalize text-gray-500 dark:text-slate-400">
{projectData.metadata?.description}
</p>
) : null}
{projectData.tags && projectData.tags.length ? (
<p>
<span className="font-medium">Tags:</span>
{projectData.tags?.map((tag) => (
<span className="ml-2 font-mono lowercase">
<Pill text={tag} />
</span>
))}
</p>
<TagList tags={projectData.tags} />
) : null}
{projectData.root ? (
<p>

View File

@ -0,0 +1,42 @@
import type { Meta, StoryObj } from '@storybook/react';
import { TagList } from './tag-list';
const meta: Meta<typeof TagList> = {
component: TagList,
title: 'TagList',
};
export default meta;
type Story = StoryObj<typeof TagList>;
export const FewTags: Story = {
args: {
tags: ['tag1', 'tag2', 'tag3'],
},
};
export const ManyTags: Story = {
args: {
tags: [
'tag1',
'tag2',
'tag3',
'tag4',
'tag5',
'tag6',
'tag7',
'tag8',
'tag9',
'tag10',
'tag11',
'tag12',
'tag13',
'tag14',
'tag15',
'tag16',
'tag17',
'tag18',
'tag19',
'tag20',
],
},
};

View File

@ -0,0 +1,78 @@
import React, { useState, useRef, useEffect } from 'react';
import { Pill } from '../pill';
interface TagListProps {
tags: string[];
}
export function TagList({ tags }: TagListProps) {
const [isExpanded, _setIsExpanded] = useState(false);
const [isOverflowing, setIsOverflowing] = useState(false);
const tagsContainerRef = useRef<HTMLSpanElement>(null);
const checkOverflow = () => {
requestAnimationFrame(() => {
if (tagsContainerRef.current) {
setIsOverflowing(
tagsContainerRef.current.scrollWidth >
tagsContainerRef.current.offsetWidth
);
}
});
};
const setExpanded = (value: boolean) => {
_setIsExpanded(value);
checkOverflow();
};
useEffect(() => {
checkOverflow();
window.addEventListener('resize', checkOverflow);
return () => window.removeEventListener('resize', checkOverflow);
}, [tagsContainerRef]);
return (
<div className="relative max-w-full">
<p className="flex min-w-0 font-medium leading-loose">
<span className="inline-block">Tags:</span>
<span
className={`inline-block ${
isExpanded ? 'whitespace-normal' : 'whitespace-nowrap'
} w-full max-w-full overflow-hidden transition-all duration-300`}
style={{
maskImage:
isOverflowing && !isExpanded
? 'linear-gradient(to right, black 80%, transparent 100%)'
: 'none',
}}
ref={tagsContainerRef}
>
{tags.map((tag) => (
<span key={tag} className="ml-2 font-mono lowercase">
<Pill text={tag} />
</span>
))}
{isExpanded && (
<button
onClick={() => setExpanded(false)}
className="inline-block px-2 align-middle"
>
Show less
</button>
)}
</span>
{isOverflowing && !isExpanded && (
<button
onClick={() => setExpanded(true)}
className="ml-1 inline-block whitespace-nowrap"
>
Show more
</button>
)}
</p>
</div>
);
}