feat(graph): update tags to render on a single line by default with expand option (#27829)
This commit is contained in:
parent
d72a1d4e6e
commit
b8486fb53f
@ -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>
|
||||
|
||||
@ -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',
|
||||
],
|
||||
},
|
||||
};
|
||||
78
graph/ui-project-details/src/lib/tag-list/tag-list.tsx
Normal file
78
graph/ui-project-details/src/lib/tag-list/tag-list.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user