@redneckz/wildless-cms-uni-blocks 0.2.53 → 0.2.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/dist/BaseTile.d.ts +13 -0
  2. package/dist/BaseTile.js +35 -0
  3. package/dist/BaseTile.js.map +1 -0
  4. package/dist/Blocks.d.ts +2 -2
  5. package/dist/Blocks.js.map +1 -1
  6. package/dist/ContentPage.d.ts +4 -1
  7. package/dist/ContentPage.js +3 -4
  8. package/dist/ContentPage.js.map +1 -1
  9. package/dist/ContentPageContext.d.ts +2 -0
  10. package/dist/ExchangeRateTile.js +7 -5
  11. package/dist/ExchangeRateTile.js.map +1 -1
  12. package/dist/Footer/Footer.mobile.d.ts +5 -0
  13. package/dist/Footer/Footer.mobile.js +7 -0
  14. package/dist/Footer/Footer.mobile.js.map +1 -0
  15. package/dist/Header/Header.js +2 -2
  16. package/dist/Header/Header.js.map +1 -1
  17. package/dist/Header/HeaderContent.d.ts +1 -1
  18. package/dist/Header/HeaderSecondaryMenu.d.ts +5 -2
  19. package/dist/Header/HeaderSecondaryMenu.js +3 -2
  20. package/dist/Header/HeaderSecondaryMenu.js.map +1 -1
  21. package/dist/MobileBlocks.d.ts +13 -0
  22. package/dist/MobileBlocks.js +27 -0
  23. package/dist/MobileBlocks.js.map +1 -0
  24. package/dist/ProductBlock.d.ts +2 -0
  25. package/dist/ProductBlock.js +7 -2
  26. package/dist/ProductBlock.js.map +1 -1
  27. package/dist/ProductBlockInner.d.ts +3 -10
  28. package/dist/ProductBlockInner.js +3 -15
  29. package/dist/ProductBlockInner.js.map +1 -1
  30. package/dist/ProductTile.d.ts +4 -13
  31. package/dist/ProductTile.js +4 -11
  32. package/dist/ProductTile.js.map +1 -1
  33. package/dist/Tile.d.ts +3 -11
  34. package/dist/Tile.js +4 -26
  35. package/dist/Tile.js.map +1 -1
  36. package/dist/api/DaDataAPI.d.ts +3 -0
  37. package/dist/api/DaDataAPI.js +33 -0
  38. package/dist/api/DaDataAPI.js.map +1 -0
  39. package/dist/api/LikeAPI.d.ts +1 -1
  40. package/dist/api/LikeAPI.js +2 -2
  41. package/dist/api/LikeAPI.js.map +1 -1
  42. package/dist/content-page-repository/ContentPageRepository.d.ts +1 -0
  43. package/dist/content-page-repository/ContentPageRepository.js +6 -0
  44. package/dist/content-page-repository/ContentPageRepository.js.map +1 -1
  45. package/dist/content-page-repository/index.d.ts +1 -0
  46. package/dist/content-page-repository/index.js +3 -1
  47. package/dist/content-page-repository/index.js.map +1 -1
  48. package/dist/content-page-repository/toMobilePage.d.ts +2 -0
  49. package/dist/content-page-repository/toMobilePage.js +23 -0
  50. package/dist/content-page-repository/toMobilePage.js.map +1 -0
  51. package/dist/index.d.ts +5 -2
  52. package/dist/index.js +7 -3
  53. package/dist/index.js.map +1 -1
  54. package/dist/types.d.ts +14 -0
  55. package/dist/utils/getCurrentPosition.d.ts +1 -0
  56. package/dist/utils/getCurrentPosition.js +5 -0
  57. package/dist/utils/getCurrentPosition.js.map +1 -0
  58. package/lib/BaseTile.d.ts +13 -0
  59. package/lib/BaseTile.js +33 -0
  60. package/lib/BaseTile.js.map +1 -0
  61. package/lib/Blocks.d.ts +2 -2
  62. package/lib/Blocks.js.map +1 -1
  63. package/lib/ContentPage.d.ts +4 -1
  64. package/lib/ContentPage.js +3 -4
  65. package/lib/ContentPage.js.map +1 -1
  66. package/lib/ContentPageContext.d.ts +2 -0
  67. package/lib/ExchangeRateTile.js +7 -5
  68. package/lib/ExchangeRateTile.js.map +1 -1
  69. package/lib/Footer/Footer.mobile.d.ts +5 -0
  70. package/lib/Footer/Footer.mobile.js +5 -0
  71. package/lib/Footer/Footer.mobile.js.map +1 -0
  72. package/lib/Header/Header.js +2 -2
  73. package/lib/Header/Header.js.map +1 -1
  74. package/lib/Header/HeaderContent.d.ts +1 -1
  75. package/lib/Header/HeaderSecondaryMenu.d.ts +5 -2
  76. package/lib/Header/HeaderSecondaryMenu.js +3 -2
  77. package/lib/Header/HeaderSecondaryMenu.js.map +1 -1
  78. package/lib/MobileBlocks.d.ts +13 -0
  79. package/lib/MobileBlocks.js +25 -0
  80. package/lib/MobileBlocks.js.map +1 -0
  81. package/lib/ProductBlock.d.ts +2 -0
  82. package/lib/ProductBlock.js +8 -3
  83. package/lib/ProductBlock.js.map +1 -1
  84. package/lib/ProductBlockInner.d.ts +3 -10
  85. package/lib/ProductBlockInner.js +3 -15
  86. package/lib/ProductBlockInner.js.map +1 -1
  87. package/lib/ProductTile.d.ts +4 -13
  88. package/lib/ProductTile.js +4 -11
  89. package/lib/ProductTile.js.map +1 -1
  90. package/lib/Tile.d.ts +3 -11
  91. package/lib/Tile.js +5 -27
  92. package/lib/Tile.js.map +1 -1
  93. package/lib/api/DaDataAPI.d.ts +3 -0
  94. package/lib/api/DaDataAPI.js +30 -0
  95. package/lib/api/DaDataAPI.js.map +1 -0
  96. package/lib/api/LikeAPI.d.ts +1 -1
  97. package/lib/api/LikeAPI.js +2 -2
  98. package/lib/api/LikeAPI.js.map +1 -1
  99. package/lib/common.css +1 -1
  100. package/lib/content-page-repository/ContentPageRepository.d.ts +1 -0
  101. package/lib/content-page-repository/ContentPageRepository.js +6 -0
  102. package/lib/content-page-repository/ContentPageRepository.js.map +1 -1
  103. package/lib/content-page-repository/index.d.ts +1 -0
  104. package/lib/content-page-repository/index.js +1 -0
  105. package/lib/content-page-repository/index.js.map +1 -1
  106. package/lib/content-page-repository/toMobilePage.d.ts +2 -0
  107. package/lib/content-page-repository/toMobilePage.js +20 -0
  108. package/lib/content-page-repository/toMobilePage.js.map +1 -0
  109. package/lib/index.d.ts +5 -2
  110. package/lib/index.js +3 -1
  111. package/lib/index.js.map +1 -1
  112. package/lib/types.d.ts +14 -0
  113. package/lib/utils/getCurrentPosition.d.ts +1 -0
  114. package/lib/utils/getCurrentPosition.js +2 -0
  115. package/lib/utils/getCurrentPosition.js.map +1 -0
  116. package/package.json +9 -3
  117. package/src/BaseTile.tsx +87 -0
  118. package/src/Blocks.ts +3 -2
  119. package/src/ContentPage.fixture.tsx +23 -3
  120. package/src/ContentPage.page.json +255 -77
  121. package/src/ContentPage.tsx +10 -5
  122. package/src/ContentPageContext.tsx +3 -0
  123. package/src/ExchangeRateTile.tsx +7 -5
  124. package/src/Footer/Footer.mobile.tsx +12 -0
  125. package/src/Header/Header.fixture.tsx +1 -1
  126. package/src/Header/Header.tsx +6 -2
  127. package/src/Header/HeaderContent.ts +1 -1
  128. package/src/Header/HeaderSecondaryMenu.tsx +48 -34
  129. package/src/MobileBlocks.ts +25 -0
  130. package/src/ProductBlock.fixture.tsx +3 -2
  131. package/src/ProductBlock.tsx +25 -3
  132. package/src/ProductBlockInner.tsx +13 -70
  133. package/src/ProductTile.fixture.tsx +31 -23
  134. package/src/ProductTile.tsx +21 -70
  135. package/src/Tile.fixture.tsx +39 -29
  136. package/src/Tile.tsx +10 -79
  137. package/src/api/DaDataAPI.ts +34 -0
  138. package/src/api/LikeAPI.ts +12 -9
  139. package/src/content-page-repository/ContentPageRepository.ts +7 -0
  140. package/src/content-page-repository/index.ts +1 -0
  141. package/src/content-page-repository/toMobilePage.ts +21 -0
  142. package/src/index.ts +14 -2
  143. package/src/setup-fixture.ts +15 -0
  144. package/src/types.ts +17 -0
  145. package/src/utils/getCurrentPosition.ts +4 -0
@@ -1,5 +1,5 @@
1
- import { JSX } from '@redneckz/uni-jsx';
2
- import { Blocks } from './Blocks'; // TODO Lazy load
1
+ import { JSX, PropsWithChildren } from '@redneckz/uni-jsx';
2
+ import type { BlockContent } from './Blocks';
3
3
  import { LikeControl } from './LikeControl';
4
4
  import { Placeholder } from './Placeholder';
5
5
  import type { BlockDef, ContentPageDef, UniBlockProps } from './types';
@@ -16,6 +16,10 @@ export type BlockDecorator<VNode = any> = (
16
16
  ) => any;
17
17
 
18
18
  export interface ContentPageProps extends UniBlockProps {
19
+ blocksRegistry: Record<
20
+ string,
21
+ (props: PropsWithChildren<UniBlockProps & BlockContent, any>, context?: any) => any
22
+ >;
19
23
  data: ContentPageDef;
20
24
  blockDecorator?: BlockDecorator;
21
25
  }
@@ -26,8 +30,9 @@ const defaultBlockDecorator: BlockDecorator = ({ blockClassName, block, render }
26
30
  export const ContentPage = JSX<ContentPageProps>(
27
31
  ({
28
32
  className,
29
- data: { style: pageStyle, blocks, likeControl, colorPalette = 'pc' },
30
33
  context,
34
+ blocksRegistry,
35
+ data: { style: pageStyle, blocks, likeControl, colorPalette = 'pc' },
31
36
  blockDecorator = defaultBlockDecorator,
32
37
  }) => {
33
38
  return (
@@ -48,11 +53,11 @@ export const ContentPage = JSX<ContentPageProps>(
48
53
 
49
54
  function renderBlock(block: BlockDef, i: number) {
50
55
  const { type } = block;
51
- if (!(type in Blocks)) {
56
+ if (!(type in blocksRegistry)) {
52
57
  console.warn(`No block with "${type}" is registered`);
53
58
  }
54
59
 
55
- const BlockComponent = Blocks[type as keyof typeof Blocks] || Placeholder;
60
+ const BlockComponent = blocksRegistry[type] || Placeholder;
56
61
  return blockDecorator(
57
62
  {
58
63
  blockClassName: style2className(block.style),
@@ -24,10 +24,13 @@ export type AsyncDataHook = <Data, Error = any>(
24
24
  fetcher: () => Promise<Data>,
25
25
  ) => { data?: Data; error?: Error };
26
26
 
27
+ export type GeolocationHook = (defaultLocation: string) => [string, () => void];
28
+
27
29
  export interface ContentPageContext {
28
30
  useRouter: () => Router;
29
31
  useState: <State>(initialState: State) => [State, (_: State) => void];
30
32
  useAsyncData: AsyncDataHook;
33
+ useGeolocation: GeolocationHook;
31
34
  useLikeService: () => LikeService;
32
35
  useSearch: () => Search;
33
36
  handlerDecorator?: HandlerDecorator;
@@ -18,10 +18,12 @@ const CURRENCY_ICONS_MAP = {
18
18
  EUR: EuroIcon,
19
19
  };
20
20
 
21
- const button: ButtonProps = {
22
- text: 'Все показатели',
23
- href: 'https://cbr.ru/currency_base/daily/',
24
- };
21
+ const buttons: ButtonProps[] = [
22
+ {
23
+ text: 'Все показатели',
24
+ href: 'https://cbr.ru/currency_base/daily/',
25
+ },
26
+ ];
25
27
 
26
28
  export const ExchangeRateTile = JSX<ExchangeRateTileProps>(({ className, context, title }) => {
27
29
  const { data } = context.useAsyncData(CBR_EXCHANGE_RATE_URL, fetchExchangeRate);
@@ -30,7 +32,7 @@ export const ExchangeRateTile = JSX<ExchangeRateTileProps>(({ className, context
30
32
  className={className}
31
33
  context={context}
32
34
  title={title || 'Курсы обмена валют'}
33
- button={button}
35
+ buttons={buttons}
34
36
  >
35
37
  <table>
36
38
  <thead>
@@ -0,0 +1,12 @@
1
+ import { JSX } from '@redneckz/uni-jsx';
2
+ import type { UniBlockProps } from '../types';
3
+ import type { FooterContent } from './Footer';
4
+ import { TextInformation } from './TextInformation';
5
+
6
+ export interface FooterProps extends FooterContent, UniBlockProps {}
7
+
8
+ export const Footer = JSX<FooterProps>(({ className, context }) => (
9
+ <footer className={`${className} px-9 py-2 bg-white rounded-bl-3xl rounded-br-3xl`}>
10
+ <TextInformation context={context} />
11
+ </footer>
12
+ ));
@@ -4,7 +4,7 @@ import { Header } from './Header';
4
4
  export default (
5
5
  <Header
6
6
  context={context}
7
- location="Москва"
7
+ defaultLocation="Москва"
8
8
  topItems={[
9
9
  {
10
10
  href: 'https://rshb.ru/',
@@ -13,7 +13,7 @@ import { isTopItemActive } from './isTopItemActive';
13
13
 
14
14
  export interface HeaderProps extends HeaderContent, UniBlockProps {}
15
15
 
16
- export const Header = JSX<HeaderProps>(({ className, location, context, topItems }) => {
16
+ export const Header = JSX<HeaderProps>(({ className, defaultLocation, context, topItems }) => {
17
17
  const router = context.useRouter();
18
18
  const sitemap = useSitemap(context.useAsyncData);
19
19
  const { handlerDecorator } = context;
@@ -46,7 +46,11 @@ export const Header = JSX<HeaderProps>(({ className, location, context, topItems
46
46
  <div className="flex items-center">
47
47
  <Logo className="mr-8" />
48
48
  {topMenu}
49
- <HeaderSecondaryMenu location={location} className="ml-auto" />
49
+ <HeaderSecondaryMenu
50
+ context={context}
51
+ className="ml-auto"
52
+ defaultLocation={defaultLocation}
53
+ />
50
54
  </div>
51
55
  <div className="mt-5 h-[1px] bg-main-divider" />
52
56
  <nav className="mt-5">{subMenu}</nav>
@@ -1,6 +1,6 @@
1
1
  import type { TopMenuItem } from '../types';
2
2
 
3
3
  export interface HeaderContent {
4
- location?: string;
4
+ defaultLocation?: string;
5
5
  topItems?: TopMenuItem[];
6
6
  }
@@ -2,41 +2,55 @@ import { JSX } from '@redneckz/uni-jsx';
2
2
  import { GridIcon, LoupeIcon, ProfileIcon } from '../Icons/index';
3
3
  import { TopItem } from '../ui-kit/TopItem';
4
4
  import { HeaderSecondaryMenuButton } from './HeaderSecondaryMenuButton';
5
+ import type { UniBlockProps } from '../types';
5
6
 
6
- interface HeaderSecondaryMenuProps {
7
- location?: string;
7
+ interface HeaderSecondaryMenuContent {
8
+ defaultLocation?: string;
8
9
  className?: string;
9
10
  }
10
11
 
11
- export const HeaderSecondaryMenu = JSX<HeaderSecondaryMenuProps>(({ location, className }) => {
12
- return (
13
- <div className={`flex items-center ${className || ''}`}>
14
- <TopItem className="mr-5" flat={true} href="#" text={location} ariaLabel="Местоположение" />
15
- <TopItem
16
- className="mr-7"
17
- flat={true}
18
- href="#"
19
- text="Офисы и банкоматы"
20
- ariaLabel="Список всех доступных офисов и банкоматов"
21
- />
22
- <HeaderSecondaryMenuButton
23
- className="mr-5 text-primary-text hover:text-primary-main"
24
- ariaLabel="Поиск по сайту"
25
- >
26
- {LoupeIcon({ 'aria-hidden': true })}
27
- </HeaderSecondaryMenuButton>
28
- <HeaderSecondaryMenuButton
29
- className="mr-5 text-primary-text hover:text-primary-main"
30
- ariaLabel="Профиль"
31
- >
32
- {ProfileIcon({ 'aria-hidden': true })}
33
- </HeaderSecondaryMenuButton>
34
- <HeaderSecondaryMenuButton
35
- className="mr-5 text-secondary-light hover:text-secondary-active min-w-[32px] min-h-[32px]"
36
- ariaLabel="Дополнительные ссылки"
37
- >
38
- {GridIcon({ 'aria-hidden': true })}
39
- </HeaderSecondaryMenuButton>
40
- </div>
41
- );
42
- });
12
+ export interface HeaderSecondaryMenuProps extends HeaderSecondaryMenuContent, UniBlockProps {}
13
+
14
+ export const HeaderSecondaryMenu = JSX<HeaderSecondaryMenuProps>(
15
+ ({ context, className, defaultLocation = '' }) => {
16
+ const [city, getCity] = context.useGeolocation(defaultLocation);
17
+
18
+ return (
19
+ <div className={`flex items-center ${className || ''}`}>
20
+ <TopItem
21
+ className="mr-5"
22
+ flat={true}
23
+ href="#"
24
+ text={city}
25
+ ariaLabel="Местоположение"
26
+ onClick={getCity}
27
+ />
28
+ <TopItem
29
+ className="mr-7"
30
+ flat={true}
31
+ href="#"
32
+ text="Офисы и банкоматы"
33
+ ariaLabel="Список всех доступных офисов и банкоматов"
34
+ />
35
+ <HeaderSecondaryMenuButton
36
+ className="mr-5 text-primary-text hover:text-primary-main"
37
+ ariaLabel="Поиск по сайту"
38
+ >
39
+ {LoupeIcon({ 'aria-hidden': true })}
40
+ </HeaderSecondaryMenuButton>
41
+ <HeaderSecondaryMenuButton
42
+ className="mr-5 text-primary-text hover:text-primary-main"
43
+ ariaLabel="Профиль"
44
+ >
45
+ {ProfileIcon({ 'aria-hidden': true })}
46
+ </HeaderSecondaryMenuButton>
47
+ <HeaderSecondaryMenuButton
48
+ className="mr-5 text-secondary-light hover:text-secondary-active min-w-[32px] min-h-[32px]"
49
+ ariaLabel="Дополнительные ссылки"
50
+ >
51
+ {GridIcon({ 'aria-hidden': true })}
52
+ </HeaderSecondaryMenuButton>
53
+ </div>
54
+ );
55
+ },
56
+ );
@@ -0,0 +1,25 @@
1
+ import { BenefitsBlock } from './BenefitsBlock';
2
+ import { ExchangeRateTile } from './ExchangeRateTile';
3
+ import { Footer } from './Footer/Footer.mobile';
4
+ import { Header } from './Header/index';
5
+ import { MobileAppTile } from './MobileAppTile';
6
+ import { Placeholder } from './Placeholder';
7
+ import { ProductBlock } from './ProductBlock';
8
+ import { ProductGallery } from './ProductGallery';
9
+ import { ProductTile } from './ProductTile';
10
+ import { StepsBlock } from './StepsBlock';
11
+ import { Tile } from './Tile';
12
+
13
+ export const MobileBlocks = {
14
+ Header,
15
+ Footer,
16
+ Placeholder,
17
+ Tile,
18
+ ProductTile,
19
+ ProductBlock,
20
+ StepsBlock,
21
+ BenefitsBlock,
22
+ ProductGallery,
23
+ ExchangeRateTile,
24
+ MobileAppTile,
25
+ };
@@ -7,8 +7,8 @@ const image: Picture = {
7
7
  src: 'money-1.png',
8
8
  format: 'webp',
9
9
  size: {
10
- width: 300,
11
- height: 300,
10
+ width: 280,
11
+ height: 280,
12
12
  },
13
13
  };
14
14
 
@@ -70,6 +70,7 @@ export default {
70
70
  context={context}
71
71
  title={'Оплата проходит \nв 180 странах мира'}
72
72
  breadcrumbs={[]}
73
+ description="Кредит наличными без залога и поручительства. Потребительский кредит на любые цели. Нужен только паспорт."
73
74
  items={[
74
75
  'Совершайте любые личные покупки',
75
76
  'Используйте корпоративную карту как обычную дебетовую, если вы ИП',
@@ -2,13 +2,35 @@ import { JSX } from '@redneckz/uni-jsx';
2
2
  import { ProductBlockInner } from './ProductBlockInner';
3
3
  import type { ProductBlockInnerContent } from './ProductBlockInner';
4
4
  import type { UniBlockProps } from './types';
5
+ import { Breadcrumb, BreadcrumbProps } from './ui-kit/Breadcrumb';
6
+ import { useLink } from './useLink';
7
+ import { joinList } from './utils/joinList';
5
8
 
6
- export interface ProductBlockProps extends ProductBlockInnerContent, UniBlockProps {}
9
+ export interface ProductBlockProps extends ProductBlockInnerContent, UniBlockProps {
10
+ breadcrumbs?: BreadcrumbProps[];
11
+ }
7
12
 
8
13
  export const ProductBlock = JSX<ProductBlockProps>((props) => {
9
- const className = props.className;
14
+ const { context, className, breadcrumbs } = props;
15
+ const router = context.useRouter();
16
+ const { handlerDecorator } = context;
10
17
  return (
11
- <section className={`bg-white p-11 pr-[7.5rem] ${className || ''}`}>
18
+ <section className={`font-sans bg-white pl-12 pr-[7.5rem] py-10 ${className || ''}`}>
19
+ {breadcrumbs?.length ? (
20
+ <div className="text-xs mb-6">
21
+ {joinList(<span className="text-secondary-text mx-2">/</span>)(
22
+ breadcrumbs.map((breadcrumb, i) => (
23
+ <Breadcrumb
24
+ key={String(i)}
25
+ {...useLink(
26
+ { router, handlerDecorator },
27
+ { className: 'text-secondary-text', ...breadcrumb },
28
+ )}
29
+ />
30
+ )),
31
+ )}
32
+ </div>
33
+ ) : null}
12
34
  <ProductBlockInner {...props} />
13
35
  </section>
14
36
  );
@@ -1,78 +1,35 @@
1
1
  import { JSX } from '@redneckz/uni-jsx';
2
2
  import { EmptyWalletIcon, PercentageSquareIcon, CalendarIcon } from './Icons/index';
3
+ import type { UniBlockProps, Benefit } from './types';
4
+ import { BaseTile } from './BaseTile';
5
+ import type { BaseTileContent } from './BaseTile';
3
6
  import { Img } from './Img';
4
- import type { Picture, UniBlockProps, Benefit } from './types';
5
- import { BlockItem } from './ui-kit/BlockItem';
6
- import type { ButtonProps } from './ui-kit/Button';
7
- import { Button } from './ui-kit/Button';
8
- import { Breadcrumb, BreadcrumbProps } from './ui-kit/Breadcrumb';
9
- import { useLink } from './useLink';
10
- import { joinList } from './utils/joinList';
11
7
 
12
8
  const ICONS = { EmptyWalletIcon, PercentageSquareIcon, CalendarIcon };
13
9
 
14
- export interface ProductBlockInnerContent {
15
- title?: string;
16
- description?: string;
17
- breadcrumbs?: BreadcrumbProps[];
18
- image?: Picture;
10
+ export interface ProductBlockInnerContent extends BaseTileContent {
19
11
  benefits?: Benefit[];
20
- items?: string[];
21
- buttons?: ButtonProps[];
22
12
  }
23
13
 
24
14
  export interface ProductBlockInnerProps extends ProductBlockInnerContent, UniBlockProps {}
25
15
 
26
16
  export const ProductBlockInner = JSX<ProductBlockInnerProps>(
27
- ({ className, context, title, description, breadcrumbs, benefits, buttons, image, items }) => {
28
- const router = context.useRouter();
29
- const { handlerDecorator } = context;
30
-
17
+ ({ className, context, title, description, benefits, buttons, image, items }) => {
31
18
  return (
32
- <div className={`font-sans flex justify-between items-stretch ${className || ''}`}>
33
- <div className="flex flex-col">
34
- {breadcrumbs?.length ? (
35
- <div className="text-xs mb-6">
36
- {joinList(<span className="text-secondary-text mx-2">/</span>)(
37
- breadcrumbs.map((breadcrumb, i) => (
38
- <Breadcrumb
39
- key={String(i)}
40
- {...useLink(
41
- { router, handlerDecorator },
42
- { className: 'text-secondary-text', ...breadcrumb },
43
- )}
44
- />
45
- )),
46
- )}
47
- </div>
48
- ) : null}
19
+ <div className={`flex justify-between items-stretch ${className || ''}`}>
20
+ <div className={'flex flex-col'}>
49
21
  {title && (
50
22
  <h1 className="font-medium text-title-lg m-0 whitespace-pre-wrap max-w-[600px]">
51
23
  {title}
52
24
  </h1>
53
25
  )}
54
- {description && (
55
- <div className="font-normal text-base max-w-[600px] mt-4">{description}</div>
56
- )}
57
- {benefits?.length ? (
58
- <div className="flex gap-6 mt-7">{benefits.map(renderBenefit)}</div>
59
- ) : null}
60
- {items?.length ? (
61
- <section className="mt-5" role="list">
62
- {items.map((_, i) => (
63
- <BlockItem className="mb-2" key={String(i)} text={_} />
64
- ))}
65
- </section>
66
- ) : null}
67
- {buttons?.length ? (
68
- <div className="flex mt-auto gap-4">
69
- {buttons.map((button, index) =>
70
- renderButton(useLink({ router, handlerDecorator }, button), index),
71
- )}
72
- </div>
73
- ) : null}
26
+ <BaseTile context={context} description={description} items={items} buttons={buttons}>
27
+ {benefits?.length ? (
28
+ <div className="flex gap-6 mt-6 mb-12">{benefits.map(renderBenefit)}</div>
29
+ ) : null}
30
+ </BaseTile>
74
31
  </div>
75
- {image?.src && <Img image={image} className="mt-auto" />}
32
+ {image?.src && <Img className="mt-auto" image={image} />}
76
33
  </div>
77
34
  );
78
35
  },
@@ -95,17 +52,3 @@ function renderBenefit(benefit: Benefit, i: number) {
95
52
  </div>
96
53
  );
97
54
  }
98
-
99
- function renderButton(button: ButtonProps, i: number) {
100
- return button?.text ? (
101
- <Button key={String(i)} {...button} className="mt-8" version={button.version} />
102
- ) : null;
103
- }
104
-
105
- function join<E>(sep: E): (list: E[]) => E[] {
106
- return (list) =>
107
- list.reduce(
108
- (acc, el, i) => (acc.length ? acc.concat({ ...sep, key: i }, el) : [el]),
109
- [] as E[],
110
- );
111
- }
@@ -43,11 +43,13 @@ export default {
43
43
  description: 'до 5 лет',
44
44
  },
45
45
  ]}
46
- button={{
47
- text: 'Подробнее',
48
- href: '/credit-cards',
49
- version: 'secondary',
50
- }}
46
+ buttons={[
47
+ {
48
+ text: 'Подробнее',
49
+ href: '/credit-cards',
50
+ version: 'secondary',
51
+ },
52
+ ]}
51
53
  image={cardWithMoney}
52
54
  />
53
55
  </div>
@@ -73,12 +75,14 @@ export default {
73
75
  description: 'до 3 лет',
74
76
  },
75
77
  ]}
76
- button={{
77
- href: 'https://rshb.ru',
78
- text: 'Подробнее',
79
- target: '_blank',
80
- version: 'secondary',
81
- }}
78
+ buttons={[
79
+ {
80
+ href: 'https://rshb.ru',
81
+ text: 'Подробнее',
82
+ target: '_blank',
83
+ version: 'secondary',
84
+ },
85
+ ]}
82
86
  image={letterWithMoney}
83
87
  />
84
88
  </div>
@@ -104,12 +108,14 @@ export default {
104
108
  description: 'до 10 лет',
105
109
  },
106
110
  ]}
107
- button={{
108
- href: 'https://rshb.ru',
109
- text: 'Подробнее',
110
- target: '_blank',
111
- version: 'secondary',
112
- }}
111
+ buttons={[
112
+ {
113
+ href: 'https://rshb.ru',
114
+ text: 'Подробнее',
115
+ target: '_blank',
116
+ version: 'secondary',
117
+ },
118
+ ]}
113
119
  image={building}
114
120
  />
115
121
  </div>
@@ -135,12 +141,14 @@ export default {
135
141
  description: 'до 5 лет',
136
142
  },
137
143
  ]}
138
- button={{
139
- href: 'https://rshb.ru',
140
- text: 'Подробнее',
141
- target: '_blank',
142
- version: 'secondary',
143
- }}
144
+ buttons={[
145
+ {
146
+ href: 'https://rshb.ru',
147
+ text: 'Подробнее',
148
+ target: '_blank',
149
+ version: 'secondary',
150
+ },
151
+ ]}
144
152
  />
145
153
  </div>
146
154
  ),
@@ -1,79 +1,30 @@
1
1
  import { JSX } from '@redneckz/uni-jsx';
2
- import type { ContentPageContext } from './ContentPageContext';
3
- import { Img } from './Img';
4
- import { BlockVersion, Picture } from './types';
5
- import type { ButtonProps } from './ui-kit/Button';
6
- import { Button } from './ui-kit/Button';
7
- import { useLink } from './useLink';
8
- import type { Benefit } from './types';
2
+ import type { UniBlockProps, Benefit } from './types';
3
+ import { BlockVersion } from './types';
4
+ import { Tile } from './Tile';
5
+ import type { BaseTileContent } from './BaseTile';
9
6
 
10
- export interface ProductTileContent {
11
- title?: string;
12
- description?: string;
7
+ export interface ProductTileContent extends BaseTileContent {
13
8
  benefits?: Benefit[];
14
- image?: Picture;
15
- button?: ButtonProps;
16
- version?: BlockVersion;
17
9
  }
18
10
 
19
- export interface ProductTileProps extends ProductTileContent {
20
- className?: string;
21
- context: ContentPageContext;
22
- }
23
-
24
- const productTileStyleMap: Record<BlockVersion, string> = {
25
- primary: 'bg-white text-primary-text',
26
- secondary: 'bg-primary-main text-white',
27
- };
11
+ export interface ProductTileProps extends ProductTileContent, UniBlockProps {}
28
12
 
29
- export const ProductTile = JSX<ProductTileProps>(
30
- ({ className, context, title, description, button, image, benefits, version = 'primary' }) => {
31
- const router = context.useRouter();
32
- const { handlerDecorator } = context;
33
- return (
34
- <section className={`font-sans p-9 ${className || ''} ${productTileStyleMap[version]}`}>
35
- <div className="flex flex-col w-full">
36
- {title && (
37
- <h3 className="font-medium text-title-sm m-0 whitespace-pre-wrap max-w-[600px]">
38
- {title}
39
- </h3>
40
- )}
41
- {description && (
42
- <div className="font-normal text-base max-w-[600px] mt-4">{description}</div>
43
- )}
44
- <div className="flex mt-5">
45
- <div className="grow flex flex-col">
46
- <div className="flex">
47
- {benefits?.length ? (
48
- <div className="mr-8">{benefits.map(renderBenefitDescription)}</div>
49
- ) : null}
50
- {benefits?.length ? (
51
- <div className="pt-1">
52
- {benefits.map((_, i) => renderBenefitLabel(_, i, version))}
53
- </div>
54
- ) : null}
55
- </div>
56
- {button?.text && (
57
- <div className="mt-auto">
58
- <Button
59
- className="mt-8"
60
- {...useLink({ router, handlerDecorator }, button)}
61
- version="secondary"
62
- />
63
- </div>
64
- )}
65
- </div>
66
- {image && (
67
- <div className="mt-auto flex-none h-[220px] w-[220px]">
68
- <Img image={image} />
69
- </div>
70
- )}
71
- </div>
72
- </div>
73
- </section>
74
- );
75
- },
76
- );
13
+ export const ProductTile = JSX<ProductTileProps>((props) => {
14
+ const { benefits, version } = props;
15
+ return (
16
+ <Tile {...props}>
17
+ <div className="flex mt-5 mb-10">
18
+ {benefits?.length ? (
19
+ <div className="mr-8">{benefits.map(renderBenefitDescription)}</div>
20
+ ) : null}
21
+ {benefits?.length ? (
22
+ <div className="pt-1">{benefits.map((_, i) => renderBenefitLabel(_, i, version))}</div>
23
+ ) : null}
24
+ </div>
25
+ </Tile>
26
+ );
27
+ });
77
28
 
78
29
  function renderBenefitLabel(benefit: Benefit, i: number, version = 'primary') {
79
30
  const labelStyleMap: Record<BlockVersion, string> = {