Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/blocks/ContentLayout/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
`properties:` — Content cube properties (optional)

- `size?: 's' | 'l'` — Cube size that defines font sizes (defaults to l)
- `size?: 's' | 'l'` — Cube size that defines font sizes ('l' by default)
- `background?: BackgroundImage` — Special background properties described in the **Content blocks** section.
- `centered?: false | true` — Indicates if text is centered (false by default).
- `theme?: 'default' | 'dark' | 'light'` — Cube theme: default, dark, or monochrome light ('default' by default).
Expand Down
30 changes: 22 additions & 8 deletions src/blocks/Tabs/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
Tabs block

`type: tabs-block` — Title
`type: tabs-block`

`title: Title` — Subtitle
`title?: Title | string`

`items: TabsBlockItem[]` — Tab description
`description?: string`

> `tabName: string` — Tab title.
`animated?: boolean` — Enables/disables animation for the block (enabled by default).

> `image: string` — Image.
`centered?: false | true` - Aligns all content to the center ('false' by default)

> `caption?: string` — Image caption.
`tabsColSizes?: Object` — Width of buttons tabs, the value ranges from 1 to 12 columns. If 12 columns, buttons takes up the entire width of the row.

> `text: string` —Text.
- `all: number` — On all screens.
- `sm: number` — On a screen wider than 577px.
- `md: number` — On a screen wider than 769px.
- `lg: number` — On a screen wider than 1081px.
- `xl: number` — On a screen wider than 1185px.

> `link?: Link` — Link below the text.
`items: TabsBlockItem[]` — Tab description

- `tabName: string` — Tab title.
- `title?: string` — Item's title
- `text?: string` — Item's text (with YFM support)
- `additionalInfo?: string` — Gray text (with YFM support)
- `links?: Link[]` — An array with link objects (see [Content blocks](?path=/story/information--common-types&viewMode=docs))
- `buttons?: Button[]` — An array with button objects (see [Content blocks](?path=/story/information--common-types&viewMode=docs))
- `image?: string | ImageObjectProps` — Image.
- [`media: Media` — Media description](?path=/story/information--common-types&viewMode=docs#media---picvideodatalens)
- `caption?: string` — Image caption.
73 changes: 62 additions & 11 deletions src/blocks/Tabs/Tabs.scss
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
@import '../../../styles/mixins';
@import '../../../styles/variables';

$block: '.#{$ns}TabsBlock';
$block: '.#{$ns}tabs-block';

#{$block} {
$class: &;

&__block-title {
margin-bottom: 12px;
margin-bottom: $indentSM;

&_centered {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin-left: auto;
margin-right: auto;
text-align: center;
}
}

&__tabs {
@include add-specificity(&) {
flex-wrap: nowrap;
overflow-x: auto;
margin-bottom: $indentM;
&_centered {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
}

&__row_reverse {
flex-direction: row-reverse;

#{$class}__content-wrapper {
margin: $indentSM $indentM 0 0;
}
}

Expand All @@ -40,6 +57,16 @@ $block: '.#{$ns}TabsBlock';
&__content {
display: flex;
flex-direction: column;

&_centered {
margin: 0 auto;
}
}

&__col {
&_centered {
margin: 0 auto;
}
}

&__content-wrapper {
Expand All @@ -58,17 +85,41 @@ $block: '.#{$ns}TabsBlock';
}
}

&__tabs,
&__link {
@include text-size(body-2);
}

@media (max-width: map-get($gridBreakpoints, 'md')) {
&__tabs {
display: flex;
flex-wrap: nowrap;
justify-content: flex-start;
overflow: auto;
margin-left: -$indentL;
margin-right: -$indentL;
padding-left: $indentL;
padding-right: $indentL - $indentXXXS;
}

&__content-wrapper {
&_margin {
margin: 0 0 $contentMargin 0;
}
}

&__row_reverse {
flex-direction: column-reverse;

#{$class}__content > * {
margin-top: $indentM;
padding-bottom: 0;
}
}
}

@media (max-width: map-get($gridBreakpoints, 'sm')) {
&__tabs {
margin-left: -$indentSM;
margin-right: -$indentSM;
padding-left: $indentSM;
padding-right: $indentXS;
}
}

@include animate(#{$class}__media);
Expand Down
152 changes: 87 additions & 65 deletions src/blocks/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,101 +1,123 @@
import React, {Fragment, useContext, useState} from 'react';
import {Tabs} from '@gravity-ui/uikit';

import {block, getThemedValue} from '../../utils';
import {Row, Col, GridColumnOrderClasses} from '../../grid';
import YFMWrapper from '../../components/YFMWrapper/YFMWrapper';
import {TabsBlockProps} from '../../models';
import AnimateBlock from '../../components/AnimateBlock/AnimateBlock';
import BlockHeader from '../../components/BlockHeader/BlockHeader';
import FullScreenImage from '../../components/FullscreenImage/FullscreenImage';
import Media from '../../components/Media/Media';
import Links from '../../components/Link/Links';
import {ThemeValueContext} from '../../context/theme/ThemeValueContext';
import {getMediaImage} from '../../components/Media/Image/utils';
import ButtonTabs, {ButtonTabsItemProps} from '../../components/ButtonTabs/ButtonTabs';
import {Content} from '../../sub-blocks';

import './Tabs.scss';

const b = block('TabsBlock');
const b = block('tabs-block');

export const TabsBlock = ({items, title, description, animated}: TabsBlockProps) => {
export const TabsBlock = ({
items,
title,
description,
animated,
tabsColSizes,
centered,
direction = 'media-content',
}: TabsBlockProps) => {
const [activeTab, setActiveTab] = useState(items[0].tabName);
const [play, setPlay] = useState<boolean>(false);
const {themeValue: theme} = useContext(ThemeValueContext);
const tabs = items.map(({tabName}) => ({title: tabName, id: tabName}));
const tabs: ButtonTabsItemProps[] = items.map(({tabName}) => ({title: tabName, id: tabName}));
const activeTabData = items.find(({tabName}) => tabName === activeTab);
const isReverse = direction === 'content-media';

let imageProps;

if (activeTabData) {
const themedImage = getThemedValue(activeTabData.image, theme);

imageProps = themedImage && getMediaImage(themedImage);
}

const showMedia = Boolean(activeTabData?.media || imageProps);
const showText = Boolean(activeTabData?.text);

const textContent = activeTabData && showText && (
<Col
sizes={{all: 12, md: showMedia ? 4 : 8}}
className={b('content', {centered: centered})}
>
<div
className={b('content-wrapper', {
margin: Boolean((activeTabData?.media || imageProps) && !isReverse),
})}
>
<Content
title={activeTabData.title}
text={activeTabData.text}
additionalInfo={activeTabData.additionalInfo}
size="s"
links={[
...(activeTabData.link ? [activeTabData.link] : []),
...(activeTabData.links || []),
]}
buttons={activeTabData.buttons}
colSizes={{all: 12}}
/>
</div>
</Col>
);

const mediaContent = showMedia && (
<Col
sizes={{all: 12, md: 8}}
orders={{
all: GridColumnOrderClasses.Last,
md: GridColumnOrderClasses.First,
}}
className={b('col', {centered: centered})}
>
{activeTabData?.media && (
<Media
{...getThemedValue(activeTabData.media, theme)}
key={activeTab}
className={b('media')}
playVideo={play}
/>
)}
{imageProps && (
<Fragment>
<FullScreenImage {...imageProps} imageClassName={b('image')} />
{activeTabData?.caption && (
<p className={b('caption')}>{activeTabData.caption}</p>
)}
</Fragment>
)}
</Col>
);

return (
<AnimateBlock className={b()} onScroll={() => setPlay(true)} animate={animated}>
<BlockHeader title={title} description={description} className={b('block-title')} />
<Tabs
className={b('tabs')}
items={tabs}
activeTab={activeTab}
onSelectTab={setActiveTab}
size="l"
<BlockHeader
title={title}
description={description}
className={b('block-title', {centered: centered})}
/>
<Row>
<Col sizes={tabsColSizes}>
<ButtonTabs
items={tabs}
onSelectTab={setActiveTab}
activeTab={activeTab}
className={b('tabs', {centered: centered})}
/>
</Col>
</Row>
{activeTabData && (
<Row>
{showMedia && (
<Col
sizes={{all: 12, md: 8}}
orders={{
all: GridColumnOrderClasses.Last,
md: GridColumnOrderClasses.First,
}}
>
{activeTabData?.media && (
<Media
{...getThemedValue(activeTabData.media, theme)}
key={activeTab}
className={b('media')}
playVideo={play}
/>
)}
{imageProps && (
<Fragment>
<FullScreenImage {...imageProps} imageClassName={b('image')} />
{activeTabData && (
<p className={b('caption')}>{activeTabData.caption}</p>
)}
</Fragment>
)}
</Col>
)}
<Col sizes={{all: 12, md: showMedia ? 4 : 8}} className={b('content')}>
<div
className={b('content-wrapper', {
margin: Boolean(activeTabData?.media || imageProps),
})}
>
<h4 className={b('content-title')}>
<YFMWrapper
content={activeTabData.title}
modifiers={{constructor: true}}
/>
</h4>
<YFMWrapper
content={activeTabData.text}
modifiers={{constructor: true}}
/>
<Links
links={[
...(activeTabData.link ? [activeTabData.link] : []),
...(activeTabData.links || []),
]}
className={b('link')}
/>
</div>
</Col>
<Row className={b('row', {reverse: isReverse})}>
{mediaContent}
{textContent}
</Row>
)}
</AnimateBlock>
Expand Down
Loading