feat(ui-toolkit,governance): description preview and read more pattern (#4599)

Co-authored-by: Joe <joe@vega.xyz>
This commit is contained in:
Sam Keen 2023-08-25 16:46:03 +01:00 committed by GitHub
parent 97f243e5f7
commit 52dea6d0dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 160 additions and 38 deletions

View File

@ -1,31 +1,15 @@
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import { useState } from 'react'; import { RoundedWrapper, ShowMore } from '@vegaprotocol/ui-toolkit';
import { useTranslation } from 'react-i18next';
import { RoundedWrapper } from '@vegaprotocol/ui-toolkit';
import { SubHeading } from '../../../../components/heading';
import { CollapsibleToggle } from '../../../../components/collapsible-toggle';
export const ProposalDescription = ({ export const ProposalDescription = ({
description, description,
}: { }: {
description: string; description: string;
}) => { }) => (
const { t } = useTranslation();
const [showDescription, setShowDescription] = useState(false);
return (
<section data-testid="proposal-description"> <section data-testid="proposal-description">
<CollapsibleToggle
toggleState={showDescription}
setToggleState={setShowDescription}
dataTestId={'proposal-description-toggle'}
>
<SubHeading title={t('proposalDescription')} />
</CollapsibleToggle>
{showDescription && (
<RoundedWrapper paddingBottom={true} marginBottomLarge={true}> <RoundedWrapper paddingBottom={true} marginBottomLarge={true}>
<div className="p-2"> <div className="p-2">
<ShowMore>
<ReactMarkdown <ReactMarkdown
className="react-markdown-container" className="react-markdown-container"
/* Prevents HTML embedded in the description from rendering */ /* Prevents HTML embedded in the description from rendering */
@ -36,9 +20,8 @@ export const ProposalDescription = ({
> >
{description} {description}
</ReactMarkdown> </ReactMarkdown>
</ShowMore>
</div> </div>
</RoundedWrapper> </RoundedWrapper>
)}
</section> </section>
); );
};

View File

@ -34,6 +34,7 @@ export * from './progress-bar';
export * from './radio-group'; export * from './radio-group';
export * from './rounded-wrapper'; export * from './rounded-wrapper';
export * from './select'; export * from './select';
export * from './show-more';
export * from './simple-grid'; export * from './simple-grid';
export * from './slider'; export * from './slider';
export * from './sparkline'; export * from './sparkline';

View File

@ -0,0 +1 @@
export * from './show-more';

View File

@ -0,0 +1,9 @@
import { render } from '@testing-library/react';
import { ShowMore } from './show-more';
describe('Button', () => {
it('should render successfully', () => {
const { baseElement } = render(<ShowMore>test</ShowMore>);
expect(baseElement).toBeTruthy();
});
});

View File

@ -0,0 +1,50 @@
import type { Story, Meta } from '@storybook/react';
import { ShowMore } from './show-more';
export default {
component: ShowMore,
title: 'ShowMore',
} as Meta;
const Template: Story = (args) => (
<ShowMore {...args}>
<p>
Spaceflight will never tolerate carelessness, incapacity, and neglect.
Somewhere, somehow, we screwed up. It could have been in design, build, or
test. Whatever it was, we should have caught it. We were too gung ho about
the schedule and we locked out all of the problems we saw each day in our
work. Every element of the program was in trouble and so were we. The
simulators were not working, Mission Control was behind in virtually every
area, and the flight and test procedures changed daily. Nothing we did had
any shelf life. Not one of us stood up and said, Dammit, stop! I dont
know what Thompsons committee will find as the cause, but I know what I
find. We are the cause! We were not ready! We did not do our job. We were
rolling the dice, hoping that things would come together by launch day,
when in our hearts we knew it would take a miracle. We were pushing the
schedule and betting that the Cape would slip before we did. From this
day forward, Flight Control will be known by two words: Tough and
Competent. Tough means we are forever accountable for what we do or what
we fail to do. We will never again compromise our responsibilities. Every
time we walk into Mission Control we will know what we stand for.
Competent means we will never take anything for granted. We will never be
found short in our knowledge and in our skills. Mission Control will be
perfect. When you leave this meeting today you will go to your office and
the first thing you will do there is to write Tough and Competent on
your blackboards. It will never be erased. Each day when you enter the
room these words will remind you of the price paid by Grissom, White, and
Chaffee. These words are the price of admission to the ranks of Mission
Control.
</p>
</ShowMore>
);
export const Default = Template.bind({});
export const CustomMaxHeight = Template.bind({});
CustomMaxHeight.args = {
closedMaxHeightPx: 50,
};
export const CustomOverlayColour = Template.bind({});
CustomOverlayColour.args = {
overlayColourOverrides: 'to-yellow-400',
};

View File

@ -0,0 +1,78 @@
import classNames from 'classnames';
import { useRef, useState, useEffect } from 'react';
import { t } from '@vegaprotocol/i18n';
import { Button } from '../button';
import type { ReactNode } from 'react';
type ShowMoreProps = {
children: ReactNode;
closedMaxHeightPx?: number;
overlayColourOverrides?: string;
};
export const ShowMore = ({
children,
closedMaxHeightPx = 125,
overlayColourOverrides,
}: ShowMoreProps) => {
const containerRef = useRef<HTMLDivElement | null>(null);
const [expanded, setExpanded] = useState(false);
useEffect(() => {
const checkHeight = () => {
const container = containerRef.current;
if (container) {
container.scrollHeight < closedMaxHeightPx
? setExpanded(true)
: setExpanded(false);
}
};
checkHeight();
window.addEventListener('resize', checkHeight);
return () => {
window.removeEventListener('resize', checkHeight);
};
}, [closedMaxHeightPx]);
const containerClasses = classNames(
'overflow-hidden transition-all ease-in-out duration-300',
{
'max-h-none': expanded,
}
);
const overlayClasses = classNames(
`absolute w-full h-16 bottom-0 left-0 transition-opacity duration-300 bg-gradient-to-b from-transparent ${
overlayColourOverrides ? overlayColourOverrides : 'to-white dark:to-black'
}`,
{
hidden: expanded,
}
);
return (
<>
<div className="relative">
<div
ref={containerRef}
className={containerClasses}
style={{ maxHeight: expanded ? 'none' : `${closedMaxHeightPx}px` }}
>
{children}
</div>
<div className={overlayClasses}></div>
</div>
{!expanded && (
<div className="mt-1 text-center">
<Button size={'sm'} onClick={() => setExpanded(true)}>
{t('Show more')}
</Button>
</div>
)}
</>
);
};