@cloud-ru/ds-uikit-product-layout 1.0.0

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 (55) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +201 -0
  3. package/README.md +137 -0
  4. package/dist/cjs/components/EmptyBlock/EmptyBlock.d.ts +36 -0
  5. package/dist/cjs/components/EmptyBlock/EmptyBlock.js +28 -0
  6. package/dist/cjs/components/EmptyBlock/index.d.ts +1 -0
  7. package/dist/cjs/components/EmptyBlock/index.js +17 -0
  8. package/dist/cjs/components/EmptyBlock/styles.module.css +24 -0
  9. package/dist/cjs/components/NoAccess/NoAccess.d.ts +12 -0
  10. package/dist/cjs/components/NoAccess/NoAccess.js +25 -0
  11. package/dist/cjs/components/NoAccess/index.d.ts +1 -0
  12. package/dist/cjs/components/NoAccess/index.js +17 -0
  13. package/dist/cjs/components/NoAccess/styles.module.css +44 -0
  14. package/dist/cjs/components/index.d.ts +2 -0
  15. package/dist/cjs/components/index.js +18 -0
  16. package/dist/cjs/constants.d.ts +10 -0
  17. package/dist/cjs/constants.js +13 -0
  18. package/dist/cjs/index.d.ts +3 -0
  19. package/dist/cjs/index.js +19 -0
  20. package/dist/cjs/locale/index.d.ts +27 -0
  21. package/dist/cjs/locale/index.js +18 -0
  22. package/dist/cjs/package.json +3 -0
  23. package/dist/cjs/style.css +68 -0
  24. package/dist/esm/components/EmptyBlock/EmptyBlock.d.ts +36 -0
  25. package/dist/esm/components/EmptyBlock/EmptyBlock.js +21 -0
  26. package/dist/esm/components/EmptyBlock/index.d.ts +1 -0
  27. package/dist/esm/components/EmptyBlock/index.js +1 -0
  28. package/dist/esm/components/EmptyBlock/styles.module.css +24 -0
  29. package/dist/esm/components/NoAccess/NoAccess.d.ts +12 -0
  30. package/dist/esm/components/NoAccess/NoAccess.js +19 -0
  31. package/dist/esm/components/NoAccess/index.d.ts +1 -0
  32. package/dist/esm/components/NoAccess/index.js +1 -0
  33. package/dist/esm/components/NoAccess/styles.module.css +44 -0
  34. package/dist/esm/components/index.d.ts +2 -0
  35. package/dist/esm/components/index.js +2 -0
  36. package/dist/esm/constants.d.ts +10 -0
  37. package/dist/esm/constants.js +10 -0
  38. package/dist/esm/index.d.ts +3 -0
  39. package/dist/esm/index.js +3 -0
  40. package/dist/esm/locale/index.d.ts +27 -0
  41. package/dist/esm/locale/index.js +15 -0
  42. package/dist/esm/style.css +68 -0
  43. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  44. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  45. package/package.json +54 -0
  46. package/src/components/EmptyBlock/EmptyBlock.tsx +82 -0
  47. package/src/components/EmptyBlock/index.ts +1 -0
  48. package/src/components/EmptyBlock/styles.module.scss +29 -0
  49. package/src/components/NoAccess/NoAccess.tsx +54 -0
  50. package/src/components/NoAccess/index.ts +1 -0
  51. package/src/components/NoAccess/styles.module.scss +47 -0
  52. package/src/components/index.ts +2 -0
  53. package/src/constants.ts +10 -0
  54. package/src/index.ts +3 -0
  55. package/src/locale/index.ts +19 -0
@@ -0,0 +1,27 @@
1
+ declare const LAYOUT_MESSAGES: {
2
+ readonly 'en-GB': {
3
+ readonly noAccessTitle: "Access restricted";
4
+ readonly noAccessSubtitle: "You do not have permission to view this content.";
5
+ readonly noAccessText: "To get access, contact your organization or project administrator.";
6
+ };
7
+ readonly 'ru-RU': {
8
+ readonly noAccessTitle: "Доступ ограничен";
9
+ readonly noAccessSubtitle: "У вас нет прав для просмотра этого контента.";
10
+ readonly noAccessText: "Для получения доступа обратитесь к администратору организации или проекта.";
11
+ };
12
+ };
13
+ export type LayoutMessages = (typeof LAYOUT_MESSAGES)['en-GB'];
14
+ /** locale пакета Layout: `layoutLocale.useTranslations()` в коде, `layoutLocale.extend(...)` в сервисе. */
15
+ export declare const layoutLocale: import("@cloud-ru/ds-locale").DefinedLocale<{
16
+ readonly 'en-GB': {
17
+ readonly noAccessTitle: "Access restricted";
18
+ readonly noAccessSubtitle: "You do not have permission to view this content.";
19
+ readonly noAccessText: "To get access, contact your organization or project administrator.";
20
+ };
21
+ readonly 'ru-RU': {
22
+ readonly noAccessTitle: "Доступ ограничен";
23
+ readonly noAccessSubtitle: "У вас нет прав для просмотра этого контента.";
24
+ readonly noAccessText: "Для получения доступа обратитесь к администратору организации или проекта.";
25
+ };
26
+ }, "@cloud-ru/ds-uikit-product-layout">;
27
+ export {};
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.layoutLocale = void 0;
4
+ const locale_1 = require("@cloud-ru/ds-locale");
5
+ const LAYOUT_MESSAGES = (0, locale_1.defineMessages)({
6
+ 'en-GB': {
7
+ noAccessTitle: 'Access restricted',
8
+ noAccessSubtitle: 'You do not have permission to view this content.',
9
+ noAccessText: 'To get access, contact your organization or project administrator.',
10
+ },
11
+ 'ru-RU': {
12
+ noAccessTitle: 'Доступ ограничен',
13
+ noAccessSubtitle: 'У вас нет прав для просмотра этого контента.',
14
+ noAccessText: 'Для получения доступа обратитесь к администратору организации или проекта.',
15
+ },
16
+ });
17
+ /** locale пакета Layout: `layoutLocale.useTranslations()` в коде, `layoutLocale.extend(...)` в сервисе. */
18
+ exports.layoutLocale = (0, locale_1.defineLocale)('@cloud-ru/ds-uikit-product-layout', LAYOUT_MESSAGES);
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,68 @@
1
+ .emptyBlock{
2
+ display:flex;
3
+ flex-grow:1;
4
+ box-sizing:border-box;
5
+ width:100%;
6
+ }
7
+ .emptyBlock > :last-child{
8
+ display:flex;
9
+ flex:1 1 auto;
10
+ width:100%;
11
+ min-width:0;
12
+ }
13
+
14
+ .inner{
15
+ display:flex;
16
+ flex:1 0 0;
17
+ align-items:center;
18
+ justify-content:center;
19
+ width:100%;
20
+ }
21
+
22
+ .infoBlock{
23
+ max-width:624px;
24
+ }
25
+ .wrapper{
26
+ position:relative;
27
+ display:flex;
28
+ flex-direction:column;
29
+ flex-grow:1;
30
+ box-sizing:border-box;
31
+ width:100%;
32
+ max-width:1200px;
33
+ min-height:100%;
34
+ }
35
+
36
+ .wrapper[data-mobile=true]{
37
+ max-width:360px;
38
+ }
39
+
40
+ .block{
41
+ display:flex;
42
+ flex:1;
43
+ flex-direction:column;
44
+ justify-content:center;
45
+ }
46
+
47
+ .serviceName{
48
+ font-family:var(--sn-thin-headline-s-fontFamily, var(--sn-brand-font-fontFamily-thin-headline, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
49
+ font-weight:var(--sn-thin-headline-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-headline-s, var(--sn-brand-font-fontWeight-light-thin-headline-s, var(--sn-primitive-font-fontWeightValue-500, 500))));
50
+ line-height:var(--sn-thin-headline-s-lineHeight, var(--sn-density-typography-roleHeadline-lineHeightS, var(--sn-primitive-font-lineHeight-by24, 32px)));
51
+ font-size:var(--sn-thin-headline-s-fontSize, var(--sn-density-typography-roleHeadline-fontSizeS, var(--sn-primitive-font-fontSize-24, 24px)));
52
+ letter-spacing:var(--sn-thin-headline-s-letterSpacing, var(--sn-primitive-font-letterSpacing-xs, -0.5px));
53
+ paragraph-spacing:var(--sn-thin-headline-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize24, 12px));
54
+ display:block;
55
+ margin-bottom:var(--sn-primitive-dimension-16, 16px);
56
+ color:var(--sn-theme-color-available-version-textMain, var(--sn-brand-color-text-version-main, #41424e));
57
+ }
58
+
59
+ .description{
60
+ max-width:500px;
61
+ margin-top:var(--sn-primitive-dimension-8, 8px);
62
+ }
63
+
64
+ .text{
65
+ display:block;
66
+ text-align:center;
67
+ white-space:break-spaces;
68
+ }
@@ -0,0 +1,36 @@
1
+ import { LayoutPresets } from '@cloud-ru/ds-adaptive';
2
+ import { IconPredefinedProps } from '@cloud-ru/ds-icon-predefined';
3
+ import { Align } from '@cloud-ru/ds-info-block';
4
+ import { WithSupportProps } from '@cloud-ru/ds-utils';
5
+ import { ReactNode } from 'react';
6
+ type EmptyBlockAdaptiveFieldProps = {
7
+ /** Выравнивание иконки и текста */
8
+ align?: Align;
9
+ };
10
+ /** Пропы `EmptyBlock`, дефолты которых меняет адаптив (preset-класс). */
11
+ type EmptyBlockLayoutDefaults = Pick<EmptyBlockAdaptiveFieldProps, 'align'>;
12
+ export type EmptyBlockProps = WithSupportProps<EmptyBlockAdaptiveFieldProps & {
13
+ /** Заголовок */
14
+ title?: string;
15
+ /** Описание под заголовком */
16
+ content?: ReactNode;
17
+ /** Иконка */
18
+ icon?: IconPredefinedProps;
19
+ /** Слот действий под текстом (например, `ButtonGroup`) */
20
+ footer?: ReactNode;
21
+ /**
22
+ * Override mobile-дефолтов адаптива для этого инстанса (deep-merge поверх `EMPTY_BLOCK_LAYOUT_PRESETS`).
23
+ * Escape-hatch: обычно не нужен — DS-пресет применяется автоматически по `AdaptiveProvider`.
24
+ */
25
+ layoutPresets?: LayoutPresets<EmptyBlockLayoutDefaults>;
26
+ /** Дополнительный класс */
27
+ className?: string;
28
+ }>;
29
+ /** DS-пресет адаптива `EmptyBlock`: на mobile — вертикальное выравнивание, desktop — горизонтальное. */
30
+ export declare const EMPTY_BLOCK_LAYOUT_PRESETS: LayoutPresets<EmptyBlockLayoutDefaults>;
31
+ /**
32
+ * Блок-заглушка для пустого состояния: иконка, заголовок, описание и опциональный
33
+ * слот действий на нейтральной подложке.
34
+ */
35
+ export declare function EmptyBlock({ title, content, icon, footer, align, layoutPresets, className, ...rest }: EmptyBlockProps): import("react/jsx-runtime").JSX.Element;
36
+ export {};
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { isMobileLayout, mergePresets, useAdaptiveLayout, useLayoutDefaults } from '@cloud-ru/ds-adaptive';
3
+ import { Block, SIZE as BLOCK_SIZE } from '@cloud-ru/ds-block';
4
+ import { ALIGN, InfoBlock, SIZE as INFO_SIZE } from '@cloud-ru/ds-info-block';
5
+ import { extractSupportProps } from '@cloud-ru/ds-utils';
6
+ import cn from 'classnames';
7
+ import styles from './styles.module.css';
8
+ /** DS-пресет адаптива `EmptyBlock`: на mobile — вертикальное выравнивание, desktop — горизонтальное. */
9
+ export const EMPTY_BLOCK_LAYOUT_PRESETS = {
10
+ mobile: { align: ALIGN.Vertical },
11
+ };
12
+ /**
13
+ * Блок-заглушка для пустого состояния: иконка, заголовок, описание и опциональный
14
+ * слот действий на нейтральной подложке.
15
+ */
16
+ export function EmptyBlock({ title, content, icon, footer, align, layoutPresets, className, ...rest }) {
17
+ const { align: resolvedAlign } = useLayoutDefaults({ align: ALIGN.Horizontal }, mergePresets(EMPTY_BLOCK_LAYOUT_PRESETS, layoutPresets), { align });
18
+ const { layoutType } = useAdaptiveLayout();
19
+ const isMobile = isMobileLayout(layoutType);
20
+ return (_jsx(Block, { size: BLOCK_SIZE.L, className: cn(styles.emptyBlock, className), ...extractSupportProps(rest), children: _jsx("div", { className: styles.inner, children: _jsx(InfoBlock, { className: styles.infoBlock, title: title, content: content, icon: icon, size: isMobile ? INFO_SIZE.M : INFO_SIZE.L, align: resolvedAlign, footer: footer }) }) }));
21
+ }
@@ -0,0 +1 @@
1
+ export * from './EmptyBlock.js';
@@ -0,0 +1 @@
1
+ export * from './EmptyBlock.js';
@@ -0,0 +1,24 @@
1
+ .emptyBlock{
2
+ display:flex;
3
+ flex-grow:1;
4
+ box-sizing:border-box;
5
+ width:100%;
6
+ }
7
+ .emptyBlock > :last-child{
8
+ display:flex;
9
+ flex:1 1 auto;
10
+ width:100%;
11
+ min-width:0;
12
+ }
13
+
14
+ .inner{
15
+ display:flex;
16
+ flex:1 0 0;
17
+ align-items:center;
18
+ justify-content:center;
19
+ width:100%;
20
+ }
21
+
22
+ .infoBlock{
23
+ max-width:624px;
24
+ }
@@ -0,0 +1,12 @@
1
+ import { WithSupportProps } from '@cloud-ru/ds-utils';
2
+ export type NoAccessProps = WithSupportProps<{
3
+ /** Заголовок над блоком (например, название сервиса) */
4
+ serviceName?: string;
5
+ /** Дополнительный класс */
6
+ className?: string;
7
+ }>;
8
+ /**
9
+ * Экран ограниченного доступа: lock-иконка и локализованное сообщение
10
+ * на нейтральной подложке, с опциональным заголовком сервиса сверху.
11
+ */
12
+ export declare function NoAccess({ serviceName, className, ...rest }: NoAccessProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { isMobileLayout, useAdaptiveLayout } from '@cloud-ru/ds-adaptive';
3
+ import { Block, SIZE as BLOCK_SIZE } from '@cloud-ru/ds-block';
4
+ import { LockSVG } from '@cloud-ru/ds-icons/interface/product';
5
+ import { InfoBlock, SIZE as INFO_SIZE } from '@cloud-ru/ds-info-block';
6
+ import { extractSupportProps } from '@cloud-ru/ds-utils';
7
+ import cn from 'classnames';
8
+ import { TEST_IDS } from '../../constants.js';
9
+ import { layoutLocale } from '../../locale/index.js';
10
+ import styles from './styles.module.css';
11
+ /**
12
+ * Экран ограниченного доступа: lock-иконка и локализованное сообщение
13
+ * на нейтральной подложке, с опциональным заголовком сервиса сверху.
14
+ */
15
+ export function NoAccess({ serviceName, className, ...rest }) {
16
+ const { layoutType } = useAdaptiveLayout();
17
+ const { t } = layoutLocale.useTranslations();
18
+ return (_jsxs("div", { className: cn(styles.wrapper, className), "data-mobile": isMobileLayout(layoutType) || undefined, ...extractSupportProps(rest), children: [serviceName && (_jsx("div", { className: styles.serviceName, "data-test-id": TEST_IDS.noAccess.serviceName, children: serviceName })), _jsx(Block, { size: BLOCK_SIZE.L, className: styles.block, children: _jsx(InfoBlock, { size: INFO_SIZE.M, icon: { icon: LockSVG }, title: t('noAccessTitle'), content: _jsxs("div", { className: styles.description, children: [_jsx("div", { className: styles.text, children: t('noAccessSubtitle') }), _jsx("div", { className: styles.text, children: t('noAccessText') })] }) }) })] }));
19
+ }
@@ -0,0 +1 @@
1
+ export * from './NoAccess.js';
@@ -0,0 +1 @@
1
+ export * from './NoAccess.js';
@@ -0,0 +1,44 @@
1
+ .wrapper{
2
+ position:relative;
3
+ display:flex;
4
+ flex-direction:column;
5
+ flex-grow:1;
6
+ box-sizing:border-box;
7
+ width:100%;
8
+ max-width:1200px;
9
+ min-height:100%;
10
+ }
11
+
12
+ .wrapper[data-mobile=true]{
13
+ max-width:360px;
14
+ }
15
+
16
+ .block{
17
+ display:flex;
18
+ flex:1;
19
+ flex-direction:column;
20
+ justify-content:center;
21
+ }
22
+
23
+ .serviceName{
24
+ font-family:var(--sn-thin-headline-s-fontFamily, var(--sn-brand-font-fontFamily-thin-headline, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
25
+ font-weight:var(--sn-thin-headline-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-headline-s, var(--sn-brand-font-fontWeight-light-thin-headline-s, var(--sn-primitive-font-fontWeightValue-500, 500))));
26
+ line-height:var(--sn-thin-headline-s-lineHeight, var(--sn-density-typography-roleHeadline-lineHeightS, var(--sn-primitive-font-lineHeight-by24, 32px)));
27
+ font-size:var(--sn-thin-headline-s-fontSize, var(--sn-density-typography-roleHeadline-fontSizeS, var(--sn-primitive-font-fontSize-24, 24px)));
28
+ letter-spacing:var(--sn-thin-headline-s-letterSpacing, var(--sn-primitive-font-letterSpacing-xs, -0.5px));
29
+ paragraph-spacing:var(--sn-thin-headline-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize24, 12px));
30
+ display:block;
31
+ margin-bottom:var(--sn-primitive-dimension-16, 16px);
32
+ color:var(--sn-theme-color-available-version-textMain, var(--sn-brand-color-text-version-main, #41424e));
33
+ }
34
+
35
+ .description{
36
+ max-width:500px;
37
+ margin-top:var(--sn-primitive-dimension-8, 8px);
38
+ }
39
+
40
+ .text{
41
+ display:block;
42
+ text-align:center;
43
+ white-space:break-spaces;
44
+ }
@@ -0,0 +1,2 @@
1
+ export * from './EmptyBlock/index.js';
2
+ export * from './NoAccess/index.js';
@@ -0,0 +1,2 @@
1
+ export * from './EmptyBlock/index.js';
2
+ export * from './NoAccess/index.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `data-test-id` внутренних слотов, которые компонент проставляет сам
3
+ * (потребитель не может адресовать их через spread `...rest`).
4
+ * Корневой `data-test-id` приходит от потребителя через support-props.
5
+ */
6
+ export declare const TEST_IDS: {
7
+ readonly noAccess: {
8
+ readonly serviceName: "no-access__service-name";
9
+ };
10
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `data-test-id` внутренних слотов, которые компонент проставляет сам
3
+ * (потребитель не может адресовать их через spread `...rest`).
4
+ * Корневой `data-test-id` приходит от потребителя через support-props.
5
+ */
6
+ export const TEST_IDS = {
7
+ noAccess: {
8
+ serviceName: 'no-access__service-name',
9
+ },
10
+ };
@@ -0,0 +1,3 @@
1
+ export * from './components/index.js';
2
+ export * from './constants.js';
3
+ export * from './locale/index.js';
@@ -0,0 +1,3 @@
1
+ export * from './components/index.js';
2
+ export * from './constants.js';
3
+ export * from './locale/index.js';
@@ -0,0 +1,27 @@
1
+ declare const LAYOUT_MESSAGES: {
2
+ readonly 'en-GB': {
3
+ readonly noAccessTitle: "Access restricted";
4
+ readonly noAccessSubtitle: "You do not have permission to view this content.";
5
+ readonly noAccessText: "To get access, contact your organization or project administrator.";
6
+ };
7
+ readonly 'ru-RU': {
8
+ readonly noAccessTitle: "Доступ ограничен";
9
+ readonly noAccessSubtitle: "У вас нет прав для просмотра этого контента.";
10
+ readonly noAccessText: "Для получения доступа обратитесь к администратору организации или проекта.";
11
+ };
12
+ };
13
+ export type LayoutMessages = (typeof LAYOUT_MESSAGES)['en-GB'];
14
+ /** locale пакета Layout: `layoutLocale.useTranslations()` в коде, `layoutLocale.extend(...)` в сервисе. */
15
+ export declare const layoutLocale: import("@cloud-ru/ds-locale").DefinedLocale<{
16
+ readonly 'en-GB': {
17
+ readonly noAccessTitle: "Access restricted";
18
+ readonly noAccessSubtitle: "You do not have permission to view this content.";
19
+ readonly noAccessText: "To get access, contact your organization or project administrator.";
20
+ };
21
+ readonly 'ru-RU': {
22
+ readonly noAccessTitle: "Доступ ограничен";
23
+ readonly noAccessSubtitle: "У вас нет прав для просмотра этого контента.";
24
+ readonly noAccessText: "Для получения доступа обратитесь к администратору организации или проекта.";
25
+ };
26
+ }, "@cloud-ru/ds-uikit-product-layout">;
27
+ export {};
@@ -0,0 +1,15 @@
1
+ import { defineLocale, defineMessages } from '@cloud-ru/ds-locale';
2
+ const LAYOUT_MESSAGES = defineMessages({
3
+ 'en-GB': {
4
+ noAccessTitle: 'Access restricted',
5
+ noAccessSubtitle: 'You do not have permission to view this content.',
6
+ noAccessText: 'To get access, contact your organization or project administrator.',
7
+ },
8
+ 'ru-RU': {
9
+ noAccessTitle: 'Доступ ограничен',
10
+ noAccessSubtitle: 'У вас нет прав для просмотра этого контента.',
11
+ noAccessText: 'Для получения доступа обратитесь к администратору организации или проекта.',
12
+ },
13
+ });
14
+ /** locale пакета Layout: `layoutLocale.useTranslations()` в коде, `layoutLocale.extend(...)` в сервисе. */
15
+ export const layoutLocale = defineLocale('@cloud-ru/ds-uikit-product-layout', LAYOUT_MESSAGES);
@@ -0,0 +1,68 @@
1
+ .emptyBlock{
2
+ display:flex;
3
+ flex-grow:1;
4
+ box-sizing:border-box;
5
+ width:100%;
6
+ }
7
+ .emptyBlock > :last-child{
8
+ display:flex;
9
+ flex:1 1 auto;
10
+ width:100%;
11
+ min-width:0;
12
+ }
13
+
14
+ .inner{
15
+ display:flex;
16
+ flex:1 0 0;
17
+ align-items:center;
18
+ justify-content:center;
19
+ width:100%;
20
+ }
21
+
22
+ .infoBlock{
23
+ max-width:624px;
24
+ }
25
+ .wrapper{
26
+ position:relative;
27
+ display:flex;
28
+ flex-direction:column;
29
+ flex-grow:1;
30
+ box-sizing:border-box;
31
+ width:100%;
32
+ max-width:1200px;
33
+ min-height:100%;
34
+ }
35
+
36
+ .wrapper[data-mobile=true]{
37
+ max-width:360px;
38
+ }
39
+
40
+ .block{
41
+ display:flex;
42
+ flex:1;
43
+ flex-direction:column;
44
+ justify-content:center;
45
+ }
46
+
47
+ .serviceName{
48
+ font-family:var(--sn-thin-headline-s-fontFamily, var(--sn-brand-font-fontFamily-thin-headline, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
49
+ font-weight:var(--sn-thin-headline-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-headline-s, var(--sn-brand-font-fontWeight-light-thin-headline-s, var(--sn-primitive-font-fontWeightValue-500, 500))));
50
+ line-height:var(--sn-thin-headline-s-lineHeight, var(--sn-density-typography-roleHeadline-lineHeightS, var(--sn-primitive-font-lineHeight-by24, 32px)));
51
+ font-size:var(--sn-thin-headline-s-fontSize, var(--sn-density-typography-roleHeadline-fontSizeS, var(--sn-primitive-font-fontSize-24, 24px)));
52
+ letter-spacing:var(--sn-thin-headline-s-letterSpacing, var(--sn-primitive-font-letterSpacing-xs, -0.5px));
53
+ paragraph-spacing:var(--sn-thin-headline-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize24, 12px));
54
+ display:block;
55
+ margin-bottom:var(--sn-primitive-dimension-16, 16px);
56
+ color:var(--sn-theme-color-available-version-textMain, var(--sn-brand-color-text-version-main, #41424e));
57
+ }
58
+
59
+ .description{
60
+ max-width:500px;
61
+ margin-top:var(--sn-primitive-dimension-8, 8px);
62
+ }
63
+
64
+ .text{
65
+ display:block;
66
+ text-align:center;
67
+ white-space:break-spaces;
68
+ }