Skip to content

Commit 7600c88

Browse files
authored
feat: create practice 2 (#12)
1 parent adb1241 commit 7600c88

File tree

6 files changed

+71
-0
lines changed

6 files changed

+71
-0
lines changed

src/app/i18n/translation.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ export const resources = {
4646
modal: {
4747
close: 'Close modal window',
4848
},
49+
collapse: {
50+
isClosed: 'Show more',
51+
isOpened: 'Hide',
52+
},
4953
},
5054
},
5155
ru: {
@@ -95,6 +99,10 @@ export const resources = {
9599
modal: {
96100
close: 'Закрыть модальное окно',
97101
},
102+
collapse: {
103+
isClosed: 'Показать больше',
104+
isOpened: 'Скрыть',
105+
},
98106
},
99107
},
100108
};

src/shared/Collapse/Collapse.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
import clsx from 'clsx';
4+
import { ICollapse } from './interfaces';
5+
import { Btn } from '../Btns';
6+
7+
export const Collapse: React.FC<ICollapse> = ({ children, showenText }) => {
8+
const contentRef = React.useRef<HTMLDivElement>(null);
9+
const [contentHeight, setContentHeight] = React.useState(0);
10+
const [isCollapseOpen, setIsCollapseOpen] = React.useState<boolean>(false);
11+
const { t } = useTranslation();
12+
13+
// Хендлер для смены состояния открытости
14+
const handleToggle = (): void => {
15+
setIsCollapseOpen((prev) => !prev);
16+
};
17+
18+
// Эффект для измерения высоты содержимого при значении флага isCollapseOpen === true
19+
React.useLayoutEffect(() => {
20+
if (isCollapseOpen && contentRef.current) {
21+
const newHeight = contentRef.current.scrollHeight;
22+
setContentHeight(newHeight);
23+
}
24+
}, [isCollapseOpen]);
25+
26+
const contentClassNames = clsx(isCollapseOpen ? 'opacity-1 mt-8' : 'opacity-0');
27+
28+
return (
29+
<div>
30+
<div className="flex justify-between items-center">
31+
<p>{showenText}</p>
32+
<Btn onClick={handleToggle}>{isCollapseOpen ? t('collapse.isOpened') : t('collapse.isClosed')}</Btn>
33+
</div>
34+
<div className={contentClassNames} style={{ height: isCollapseOpen ? `${contentHeight}px` : 0 }}>
35+
{children}
36+
</div>
37+
</div>
38+
);
39+
};

src/shared/Collapse/interfaces.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface ICollapse {
2+
children: React.ReactNode;
3+
showenText: string;
4+
}

src/shared/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './Btns';
2+
export { Collapse } from './Collapse/Collapse';
23
export { Counter } from './Counter/Counter';
34
export { Input } from './Input/Input';
45
export { Logo } from './Logo/Logo';

src/shared/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './Btns/interfaces';
2+
export * from './Collapse/interfaces';
23
export * from './Counter/interfaces';
34
export * from './Logo/interfaces';
45
export * from './RangeSlider/interfaces';

src/stories/Collapse.stories.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { Meta } from '@storybook/react';
2+
import { Collapse } from '../shared';
3+
4+
const meta: Meta<typeof Collapse> = {
5+
title: 'UI/Collapse',
6+
component: Collapse,
7+
tags: ['autodocs'],
8+
};
9+
10+
export default meta;
11+
12+
export const Closed = {
13+
args: {
14+
showenText: 'Some text...',
15+
children:
16+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vestibulum metus at felis eleifend, at ornare lacus scelerisque. Praesent arcu mi, suscipit eu rhoncus ut, finibus a elit. Nulla finibus nisi orci. Sed vestibulum lectus ac semper porta. Proin et pharetra ipsum. Nulla vitae sem ut libero bibendum ultrices sit amet varius ipsum. Phasellus et ultrices orci. Nam pretium, erat ut ornare porta, nunc nulla vulputate dolor, ut hendrerit justo massa sed lorem. ',
17+
},
18+
};

0 commit comments

Comments
 (0)