@cloud-ru/ds-uikit-product-quota 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.
- package/CHANGELOG.md +8 -0
- package/LICENSE +201 -0
- package/README.md +458 -0
- package/dist/cjs/components/QuotaWidget/QuotaIncreaseButton.d.ts +4 -0
- package/dist/cjs/components/QuotaWidget/QuotaIncreaseButton.js +15 -0
- package/dist/cjs/components/QuotaWidget/QuotaMobileHeader.d.ts +4 -0
- package/dist/cjs/components/QuotaWidget/QuotaMobileHeader.js +15 -0
- package/dist/cjs/components/QuotaWidget/QuotaWidget.d.ts +12 -0
- package/dist/cjs/components/QuotaWidget/QuotaWidget.js +44 -0
- package/dist/cjs/components/QuotaWidget/QuotaWidgetContent.d.ts +27 -0
- package/dist/cjs/components/QuotaWidget/QuotaWidgetContent.js +33 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/ProjectHeader.d.ts +7 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/ProjectHeader.js +19 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/index.d.ts +1 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/index.js +17 -0
- package/dist/cjs/components/QuotaWidget/components/ProjectHeader/styles.module.css +30 -0
- package/dist/cjs/components/QuotaWidget/index.d.ts +2 -0
- package/dist/cjs/components/QuotaWidget/index.js +18 -0
- package/dist/cjs/components/QuotaWidget/styles.module.css +49 -0
- package/dist/cjs/components/QuotaWidgetCard/QuotaWidgetCard.d.ts +13 -0
- package/dist/cjs/components/QuotaWidgetCard/QuotaWidgetCard.js +53 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.d.ts +6 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.js +23 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/index.d.ts +1 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/index.js +17 -0
- package/dist/cjs/components/QuotaWidgetCard/components/QuotaTooltip/styles.module.css +34 -0
- package/dist/cjs/components/QuotaWidgetCard/index.d.ts +1 -0
- package/dist/cjs/components/QuotaWidgetCard/index.js +17 -0
- package/dist/cjs/components/QuotaWidgetCard/styles.module.css +97 -0
- package/dist/cjs/components/QuotaWidgetMini/QuotaWidgetMini.d.ts +7 -0
- package/dist/cjs/components/QuotaWidgetMini/QuotaWidgetMini.js +27 -0
- package/dist/cjs/components/QuotaWidgetMini/index.d.ts +1 -0
- package/dist/cjs/components/QuotaWidgetMini/index.js +17 -0
- package/dist/cjs/components/QuotaWidgetMini/styles.module.css +15 -0
- package/dist/cjs/components/index.d.ts +3 -0
- package/dist/cjs/components/index.js +19 -0
- package/dist/cjs/constants.d.ts +17 -0
- package/dist/cjs/constants.js +20 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/QuotaCardsGrid.d.ts +6 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/QuotaCardsGrid.js +32 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/Grid.d.ts +6 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/Grid.js +30 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.d.ts +6 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.js +16 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.d.ts +1 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.js +17 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/styles.module.css +10 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/index.d.ts +1 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/index.js +17 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/Grid/styles.module.css +9 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.d.ts +5 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.js +12 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/QuotaError/index.d.ts +1 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/components/QuotaError/index.js +17 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/index.d.ts +1 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/index.js +17 -0
- package/dist/cjs/helperComponents/QuotaCardsGrid/styles.module.css +16 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +21 -0
- package/dist/cjs/locale/index.d.ts +91 -0
- package/dist/cjs/locale/index.js +50 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/style.css +260 -0
- package/dist/cjs/types.d.ts +34 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/utils/checkIsExceeded.d.ts +2 -0
- package/dist/cjs/utils/checkIsExceeded.js +5 -0
- package/dist/cjs/utils/formatNumber.d.ts +1 -0
- package/dist/cjs/utils/formatNumber.js +6 -0
- package/dist/cjs/utils/getPercent.d.ts +2 -0
- package/dist/cjs/utils/getPercent.js +9 -0
- package/dist/cjs/utils/index.d.ts +3 -0
- package/dist/cjs/utils/index.js +19 -0
- package/dist/esm/components/QuotaWidget/QuotaIncreaseButton.d.ts +4 -0
- package/dist/esm/components/QuotaWidget/QuotaIncreaseButton.js +9 -0
- package/dist/esm/components/QuotaWidget/QuotaMobileHeader.d.ts +4 -0
- package/dist/esm/components/QuotaWidget/QuotaMobileHeader.js +9 -0
- package/dist/esm/components/QuotaWidget/QuotaWidget.d.ts +12 -0
- package/dist/esm/components/QuotaWidget/QuotaWidget.js +41 -0
- package/dist/esm/components/QuotaWidget/QuotaWidgetContent.d.ts +27 -0
- package/dist/esm/components/QuotaWidget/QuotaWidgetContent.js +27 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/ProjectHeader.d.ts +7 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/ProjectHeader.js +13 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/index.d.ts +1 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/index.js +1 -0
- package/dist/esm/components/QuotaWidget/components/ProjectHeader/styles.module.css +30 -0
- package/dist/esm/components/QuotaWidget/index.d.ts +2 -0
- package/dist/esm/components/QuotaWidget/index.js +2 -0
- package/dist/esm/components/QuotaWidget/styles.module.css +49 -0
- package/dist/esm/components/QuotaWidgetCard/QuotaWidgetCard.d.ts +13 -0
- package/dist/esm/components/QuotaWidgetCard/QuotaWidgetCard.js +47 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.d.ts +6 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.js +17 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/index.d.ts +1 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/index.js +1 -0
- package/dist/esm/components/QuotaWidgetCard/components/QuotaTooltip/styles.module.css +34 -0
- package/dist/esm/components/QuotaWidgetCard/index.d.ts +1 -0
- package/dist/esm/components/QuotaWidgetCard/index.js +1 -0
- package/dist/esm/components/QuotaWidgetCard/styles.module.css +97 -0
- package/dist/esm/components/QuotaWidgetMini/QuotaWidgetMini.d.ts +7 -0
- package/dist/esm/components/QuotaWidgetMini/QuotaWidgetMini.js +21 -0
- package/dist/esm/components/QuotaWidgetMini/index.d.ts +1 -0
- package/dist/esm/components/QuotaWidgetMini/index.js +1 -0
- package/dist/esm/components/QuotaWidgetMini/styles.module.css +15 -0
- package/dist/esm/components/index.d.ts +3 -0
- package/dist/esm/components/index.js +3 -0
- package/dist/esm/constants.d.ts +17 -0
- package/dist/esm/constants.js +17 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/QuotaCardsGrid.d.ts +6 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/QuotaCardsGrid.js +26 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/Grid.d.ts +6 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/Grid.js +24 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.d.ts +6 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.js +10 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.d.ts +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.js +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/styles.module.css +10 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/index.d.ts +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/index.js +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/Grid/styles.module.css +9 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.d.ts +5 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.js +9 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/QuotaError/index.d.ts +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/components/QuotaError/index.js +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/index.d.ts +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/index.js +1 -0
- package/dist/esm/helperComponents/QuotaCardsGrid/styles.module.css +16 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/locale/index.d.ts +91 -0
- package/dist/esm/locale/index.js +47 -0
- package/dist/esm/style.css +260 -0
- package/dist/esm/types.d.ts +34 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils/checkIsExceeded.d.ts +2 -0
- package/dist/esm/utils/checkIsExceeded.js +1 -0
- package/dist/esm/utils/formatNumber.d.ts +1 -0
- package/dist/esm/utils/formatNumber.js +3 -0
- package/dist/esm/utils/getPercent.d.ts +2 -0
- package/dist/esm/utils/getPercent.js +6 -0
- package/dist/esm/utils/index.d.ts +3 -0
- package/dist/esm/utils/index.js +3 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +63 -0
- package/src/components/QuotaWidget/QuotaIncreaseButton.tsx +21 -0
- package/src/components/QuotaWidget/QuotaMobileHeader.tsx +18 -0
- package/src/components/QuotaWidget/QuotaWidget.tsx +109 -0
- package/src/components/QuotaWidget/QuotaWidgetContent.tsx +91 -0
- package/src/components/QuotaWidget/components/ProjectHeader/ProjectHeader.tsx +59 -0
- package/src/components/QuotaWidget/components/ProjectHeader/index.ts +1 -0
- package/src/components/QuotaWidget/components/ProjectHeader/styles.module.scss +29 -0
- package/src/components/QuotaWidget/index.ts +2 -0
- package/src/components/QuotaWidget/styles.module.scss +52 -0
- package/src/components/QuotaWidgetCard/QuotaWidgetCard.tsx +127 -0
- package/src/components/QuotaWidgetCard/components/QuotaTooltip/QuotaTooltip.tsx +48 -0
- package/src/components/QuotaWidgetCard/components/QuotaTooltip/index.ts +1 -0
- package/src/components/QuotaWidgetCard/components/QuotaTooltip/styles.module.scss +30 -0
- package/src/components/QuotaWidgetCard/index.ts +1 -0
- package/src/components/QuotaWidgetCard/styles.module.scss +97 -0
- package/src/components/QuotaWidgetMini/QuotaWidgetMini.tsx +93 -0
- package/src/components/QuotaWidgetMini/index.ts +1 -0
- package/src/components/QuotaWidgetMini/styles.module.scss +18 -0
- package/src/components/index.ts +3 -0
- package/src/constants.ts +17 -0
- package/src/helperComponents/QuotaCardsGrid/QuotaCardsGrid.tsx +54 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/Grid.tsx +47 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/QuotaCardsSkeleton.tsx +24 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/index.ts +1 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/components/QuotaWidgetCardsSkeleton/styles.module.scss +15 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/index.ts +1 -0
- package/src/helperComponents/QuotaCardsGrid/components/Grid/styles.module.scss +12 -0
- package/src/helperComponents/QuotaCardsGrid/components/QuotaError/QuotaError.tsx +31 -0
- package/src/helperComponents/QuotaCardsGrid/components/QuotaError/index.ts +1 -0
- package/src/helperComponents/QuotaCardsGrid/index.ts +1 -0
- package/src/helperComponents/QuotaCardsGrid/styles.module.scss +16 -0
- package/src/index.ts +5 -0
- package/src/locale/index.ts +51 -0
- package/src/types.ts +35 -0
- package/src/utils/checkIsExceeded.ts +3 -0
- package/src/utils/formatNumber.ts +3 -0
- package/src/utils/getPercent.ts +9 -0
- package/src/utils/index.ts +3 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { isMobileLayout, useAdaptiveLayout } from '@cloud-ru/ds-adaptive';
|
|
2
|
+
import { Button, ButtonProps } from '@cloud-ru/ds-button';
|
|
3
|
+
import { Dropdown } from '@cloud-ru/ds-dropdown';
|
|
4
|
+
import { ChevronDownSVG, ChevronUpSVG } from '@cloud-ru/ds-icons/interface/system';
|
|
5
|
+
import { WithSupportProps } from '@cloud-ru/ds-utils';
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import { TEST_IDS } from '../../constants';
|
|
9
|
+
import { quotaLocale } from '../../locale';
|
|
10
|
+
import { QuotaWidgetPropsBase } from '../../types';
|
|
11
|
+
import { checkIsExceeded } from '../../utils';
|
|
12
|
+
import { QuotaIncreaseButton } from './QuotaIncreaseButton';
|
|
13
|
+
import { QuotaMobileHeader } from './QuotaMobileHeader';
|
|
14
|
+
import { QuotaWidgetContent } from './QuotaWidgetContent';
|
|
15
|
+
|
|
16
|
+
export type QuotaWidgetProps = WithSupportProps<
|
|
17
|
+
QuotaWidgetPropsBase & {
|
|
18
|
+
/** Ссылка на страницу квот по проекту */
|
|
19
|
+
quotasUrl: string;
|
|
20
|
+
/** Колбек клика по ссылке на страницу квот по проекту */
|
|
21
|
+
onQuotasUrlClick?: () => void;
|
|
22
|
+
/** Свойства кнопки открытия виджета */
|
|
23
|
+
buttonProps?: Pick<ButtonProps, 'size' | 'className' | 'fullWidth' | 'label' | 'appearance' | 'disabled' | 'view'>;
|
|
24
|
+
}
|
|
25
|
+
>;
|
|
26
|
+
|
|
27
|
+
export function QuotaWidget({
|
|
28
|
+
quotas,
|
|
29
|
+
disableSorting,
|
|
30
|
+
loading,
|
|
31
|
+
error,
|
|
32
|
+
onRefresh,
|
|
33
|
+
projectName,
|
|
34
|
+
quotasUrl,
|
|
35
|
+
canEditQuota,
|
|
36
|
+
hideIncreaseQuotaButton,
|
|
37
|
+
onIncreaseQuotaClick,
|
|
38
|
+
onWidgetOpen,
|
|
39
|
+
onQuotasUrlClick,
|
|
40
|
+
buttonProps,
|
|
41
|
+
...props
|
|
42
|
+
}: QuotaWidgetProps) {
|
|
43
|
+
const { t } = quotaLocale.useTranslations();
|
|
44
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
45
|
+
const { layoutType } = useAdaptiveLayout();
|
|
46
|
+
const isMobile = isMobileLayout(layoutType);
|
|
47
|
+
const rootTestId = props['data-test-id'] as string | undefined;
|
|
48
|
+
const useMatrixTestIds = Boolean(rootTestId && rootTestId !== TEST_IDS.quotaWidget.root);
|
|
49
|
+
const contentTestId = useMatrixTestIds && rootTestId ? `content-${rootTestId}` : TEST_IDS.quotaWidget.content;
|
|
50
|
+
const triggerTestId = useMatrixTestIds && rootTestId ? `trigger-${rootTestId}` : TEST_IDS.quotaWidget.trigger;
|
|
51
|
+
|
|
52
|
+
const handleOpenChange = (open: boolean) => {
|
|
53
|
+
setIsOpen(open);
|
|
54
|
+
if (open) {
|
|
55
|
+
onWidgetOpen?.();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const exhaustedCount = quotas.filter(checkIsExceeded).length;
|
|
60
|
+
|
|
61
|
+
// На мобилке лист full-height (snap `1`): шапку и кнопку выносим в pinned-слоты BottomSheet
|
|
62
|
+
// (`title` сверху, `footer` снизу), а карточки скроллятся в теле листа — как в макете.
|
|
63
|
+
const showMobileIncreaseButton = isMobile && canEditQuota && !error && !hideIncreaseQuotaButton;
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Dropdown
|
|
67
|
+
{...props}
|
|
68
|
+
placement='bottom-end'
|
|
69
|
+
// Mobile: лист на всю высоту экрана (число `1` = full-height snap; safe-area даёт сам BottomSheet).
|
|
70
|
+
snapPoints={[1]}
|
|
71
|
+
title={isMobile ? <QuotaMobileHeader projectName={projectName} /> : undefined}
|
|
72
|
+
footer={showMobileIncreaseButton ? <QuotaIncreaseButton onClick={onIncreaseQuotaClick} /> : undefined}
|
|
73
|
+
open={isOpen}
|
|
74
|
+
onOpenChange={handleOpenChange}
|
|
75
|
+
content={
|
|
76
|
+
<QuotaWidgetContent
|
|
77
|
+
quotas={quotas}
|
|
78
|
+
disableSorting={disableSorting}
|
|
79
|
+
loading={loading}
|
|
80
|
+
error={error}
|
|
81
|
+
onRefresh={onRefresh}
|
|
82
|
+
projectName={projectName}
|
|
83
|
+
quotasUrl={quotasUrl}
|
|
84
|
+
canEditQuota={canEditQuota}
|
|
85
|
+
hideIncreaseQuotaButton={hideIncreaseQuotaButton}
|
|
86
|
+
onIncreaseQuotaClick={onIncreaseQuotaClick}
|
|
87
|
+
onQuotasUrlClick={onQuotasUrlClick}
|
|
88
|
+
hideMobileHeader={isMobile}
|
|
89
|
+
hideMobileIncreaseButton={isMobile}
|
|
90
|
+
data-test-id={contentTestId}
|
|
91
|
+
/>
|
|
92
|
+
}
|
|
93
|
+
>
|
|
94
|
+
<Button
|
|
95
|
+
// На мобилке триггер бордюрный (`outline` — как в макете кнопки квот),
|
|
96
|
+
// на desktop — плоский `function`. Переопределяется через `buttonProps.view`.
|
|
97
|
+
view={isMobile ? 'outline' : 'function'}
|
|
98
|
+
label={t('quotas')}
|
|
99
|
+
appearance='neutral'
|
|
100
|
+
iconPosition='after'
|
|
101
|
+
icon={isOpen ? <ChevronUpSVG /> : <ChevronDownSVG />}
|
|
102
|
+
counter={exhaustedCount > 0 ? { value: exhaustedCount, appearance: 'red' } : undefined}
|
|
103
|
+
size='m'
|
|
104
|
+
data-test-id={triggerTestId}
|
|
105
|
+
{...buttonProps}
|
|
106
|
+
/>
|
|
107
|
+
</Dropdown>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { isMobileLayout, useAdaptiveLayout } from '@cloud-ru/ds-adaptive';
|
|
2
|
+
import { WithSupportProps } from '@cloud-ru/ds-utils';
|
|
3
|
+
|
|
4
|
+
import { TEST_IDS } from '../../constants';
|
|
5
|
+
import { QuotaCardsGrid } from '../../helperComponents/QuotaCardsGrid';
|
|
6
|
+
import { QuotaWidgetPropsBase } from '../../types';
|
|
7
|
+
import { ProjectHeader } from './components/ProjectHeader';
|
|
8
|
+
import { QuotaIncreaseButton } from './QuotaIncreaseButton';
|
|
9
|
+
import { QuotaMobileHeader } from './QuotaMobileHeader';
|
|
10
|
+
import styles from './styles.module.scss';
|
|
11
|
+
|
|
12
|
+
export type QuotaWidgetContentProps = WithSupportProps<
|
|
13
|
+
QuotaWidgetPropsBase & {
|
|
14
|
+
/** Ссылка на страницу квот по проекту */
|
|
15
|
+
quotasUrl: string;
|
|
16
|
+
/** Колбек клика по ссылке на страницу квот по проекту */
|
|
17
|
+
onQuotasUrlClick?: () => void;
|
|
18
|
+
/**
|
|
19
|
+
* Не рендерить мобильную шапку (её выносят в pinned-`title` контейнера, напр. BottomSheet).
|
|
20
|
+
* На desktop не влияет.
|
|
21
|
+
*/
|
|
22
|
+
hideMobileHeader?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Не рендерить мобильную кнопку расширения (её выносят в pinned-`footer` контейнера).
|
|
25
|
+
* На desktop не влияет.
|
|
26
|
+
*/
|
|
27
|
+
hideMobileIncreaseButton?: boolean;
|
|
28
|
+
}
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Голый контент квота-виджета: шапка проекта + карточки + кнопка расширения — без триггера,
|
|
33
|
+
* дропдауна и аккордеона. Используется внутри `QuotaWidget` (в дропдауне/BottomSheet) и напрямую,
|
|
34
|
+
* когда контейнер-раскрытие даёт кто-то снаружи (напр. `sideBlock` формы уже открывает BottomSheet).
|
|
35
|
+
*
|
|
36
|
+
* На full-height BottomSheet шапка/кнопка уезжают в pinned-слоты `title`/`footer` (см. `QuotaWidget`),
|
|
37
|
+
* а сюда остаются только карточки — тогда `hideMobileHeader`/`hideMobileIncreaseButton` = true.
|
|
38
|
+
*/
|
|
39
|
+
export function QuotaWidgetContent({
|
|
40
|
+
quotas,
|
|
41
|
+
disableSorting,
|
|
42
|
+
loading,
|
|
43
|
+
error,
|
|
44
|
+
onRefresh,
|
|
45
|
+
projectName,
|
|
46
|
+
quotasUrl,
|
|
47
|
+
canEditQuota,
|
|
48
|
+
hideIncreaseQuotaButton,
|
|
49
|
+
onIncreaseQuotaClick,
|
|
50
|
+
onQuotasUrlClick,
|
|
51
|
+
hideMobileHeader = false,
|
|
52
|
+
hideMobileIncreaseButton = false,
|
|
53
|
+
...props
|
|
54
|
+
}: QuotaWidgetContentProps) {
|
|
55
|
+
const { layoutType } = useAdaptiveLayout();
|
|
56
|
+
const isMobile = isMobileLayout(layoutType);
|
|
57
|
+
const contentTestId = props['data-test-id'] ?? TEST_IDS.quotaWidget.content;
|
|
58
|
+
|
|
59
|
+
const showMobileIncreaseButton =
|
|
60
|
+
isMobile && !hideMobileIncreaseButton && canEditQuota && !error && !hideIncreaseQuotaButton;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div className={styles.content} data-mobile={isMobile} data-test-id={contentTestId}>
|
|
64
|
+
{isMobile ? (
|
|
65
|
+
// Мобильная шапка (макет): «Квоты» + имя проекта, без пиктограммы/ссылки/подзаголовка «Остаток…».
|
|
66
|
+
!hideMobileHeader && <QuotaMobileHeader projectName={projectName} />
|
|
67
|
+
) : (
|
|
68
|
+
// Desktop-popover: полная шапка проекта (с пиктограммой, ссылкой и кнопкой расширения).
|
|
69
|
+
<ProjectHeader
|
|
70
|
+
projectName={projectName}
|
|
71
|
+
quotasUrl={quotasUrl}
|
|
72
|
+
canEditQuota={canEditQuota}
|
|
73
|
+
error={error}
|
|
74
|
+
onIncreaseQuotaClick={onIncreaseQuotaClick}
|
|
75
|
+
hideIncreaseQuotaButton={hideIncreaseQuotaButton}
|
|
76
|
+
onQuotasUrlClick={onQuotasUrlClick}
|
|
77
|
+
/>
|
|
78
|
+
)}
|
|
79
|
+
|
|
80
|
+
<QuotaCardsGrid
|
|
81
|
+
quotas={quotas}
|
|
82
|
+
disableSorting={disableSorting}
|
|
83
|
+
loading={loading}
|
|
84
|
+
error={error}
|
|
85
|
+
onRefresh={onRefresh}
|
|
86
|
+
/>
|
|
87
|
+
|
|
88
|
+
{showMobileIncreaseButton && <QuotaIncreaseButton onClick={onIncreaseQuotaClick} />}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Button } from '@cloud-ru/ds-button';
|
|
2
|
+
import { QuotaSVG } from '@cloud-ru/ds-icons/interface/product';
|
|
3
|
+
import { TitleClickable } from '@cloud-ru/ds-uikit-product-title-clickable';
|
|
4
|
+
|
|
5
|
+
import { TEST_IDS } from '../../../../constants';
|
|
6
|
+
import { quotaLocale } from '../../../../locale';
|
|
7
|
+
import { QuotaWidgetPropsBase } from '../../../../types';
|
|
8
|
+
import styles from './styles.module.scss';
|
|
9
|
+
|
|
10
|
+
type ProjectHeaderProps = Pick<
|
|
11
|
+
QuotaWidgetPropsBase,
|
|
12
|
+
'projectName' | 'canEditQuota' | 'error' | 'hideIncreaseQuotaButton' | 'onIncreaseQuotaClick'
|
|
13
|
+
> & {
|
|
14
|
+
quotasUrl: string;
|
|
15
|
+
onQuotasUrlClick?: () => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const RUSSIAN_CHARS_REGEXP = /[А-Яа-яЁё]/;
|
|
19
|
+
|
|
20
|
+
export function ProjectHeader({
|
|
21
|
+
projectName,
|
|
22
|
+
quotasUrl,
|
|
23
|
+
canEditQuota,
|
|
24
|
+
error,
|
|
25
|
+
onIncreaseQuotaClick,
|
|
26
|
+
hideIncreaseQuotaButton,
|
|
27
|
+
onQuotasUrlClick,
|
|
28
|
+
}: ProjectHeaderProps) {
|
|
29
|
+
const { t } = quotaLocale.useTranslations();
|
|
30
|
+
|
|
31
|
+
const widgetTitle = RUSSIAN_CHARS_REGEXP.test(projectName) ? 'widgetTitle.quotes' : 'widgetTitle.noQuotes';
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div className={styles.header} data-test-id={TEST_IDS.quotaWidget.projectHeader}>
|
|
35
|
+
<div className={styles.projectWrapper}>
|
|
36
|
+
<TitleClickable
|
|
37
|
+
className={styles.titleLink}
|
|
38
|
+
title={t(widgetTitle, { project: projectName })}
|
|
39
|
+
href={quotasUrl}
|
|
40
|
+
target='_blank'
|
|
41
|
+
icon={<QuotaSVG />}
|
|
42
|
+
onClick={onQuotasUrlClick}
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
<p className={styles.subtitle}>{t('widgetSubtitle')}</p>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
{canEditQuota && !error && !hideIncreaseQuotaButton && (
|
|
49
|
+
<Button
|
|
50
|
+
view='outline'
|
|
51
|
+
appearance='neutral'
|
|
52
|
+
label={t('increaseQuota')}
|
|
53
|
+
size='m'
|
|
54
|
+
onClick={onIncreaseQuotaClick}
|
|
55
|
+
/>
|
|
56
|
+
)}
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ProjectHeader';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
|
|
3
|
+
.header {
|
|
4
|
+
display: flex;
|
|
5
|
+
gap: base.$sn-primitive-dimension-8;
|
|
6
|
+
align-items: center;
|
|
7
|
+
width: 100%;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.projectWrapper {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex: 1 0 0;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
align-items: flex-start;
|
|
15
|
+
|
|
16
|
+
min-width: 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.titleLink {
|
|
20
|
+
gap: base.$sn-primitive-dimension-8;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.subtitle {
|
|
24
|
+
@include base.composite-var(base.$base-styles, 'sn', 'regular', 'body', 's');
|
|
25
|
+
|
|
26
|
+
width: 100%;
|
|
27
|
+
margin: 0;
|
|
28
|
+
color: base.$sn-theme-color-available-version-textTertiary;
|
|
29
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
|
|
3
|
+
.content {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
gap: base.$sn-primitive-dimension-16;
|
|
7
|
+
align-items: flex-start;
|
|
8
|
+
|
|
9
|
+
width: 620px;
|
|
10
|
+
min-width: 620px;
|
|
11
|
+
padding: base.$sn-primitive-dimension-12 base.$sn-primitive-dimension-16;
|
|
12
|
+
|
|
13
|
+
/* Mobile: dropdown раскрывается в BottomSheet на всю ширину экрана — фиксированные 620px дают
|
|
14
|
+
горизонтальный overflow, поэтому тянемся по контейнеру. Padding убираем: body-инсет уже даёт
|
|
15
|
+
контейнер (BottomSheet / ModalCustom), собственный padding был бы двойным. */
|
|
16
|
+
&[data-mobile='true'] {
|
|
17
|
+
width: 100%;
|
|
18
|
+
min-width: 0;
|
|
19
|
+
height: 100%;
|
|
20
|
+
padding: 0;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Кнопка «Увеличить квоту» внизу BottomSheet на мобилке — на всю ширину. */
|
|
25
|
+
.increaseButton {
|
|
26
|
+
width: 100%;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Мобильная шапка (макет): заголовок + имя проекта, слева, без пиктограмм/ссылок. */
|
|
30
|
+
.mobileHeader {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
gap: base.$sn-primitive-dimension-2;
|
|
34
|
+
align-items: flex-start;
|
|
35
|
+
|
|
36
|
+
width: 100%;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.mobileTitle {
|
|
40
|
+
@include base.composite-var(base.$base-styles, 'sn', 'regular', 'title', 'l');
|
|
41
|
+
|
|
42
|
+
margin: 0;
|
|
43
|
+
color: base.$sn-theme-color-available-version-textMain;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.mobileSubtitle {
|
|
47
|
+
@include base.composite-var(base.$base-styles, 'sn', 'regular', 'body', 'm');
|
|
48
|
+
|
|
49
|
+
width: 100%;
|
|
50
|
+
margin: 0;
|
|
51
|
+
color: base.$sn-theme-color-available-version-textSecondary;
|
|
52
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Button } from '@cloud-ru/ds-button';
|
|
2
|
+
import { UpdateSVG } from '@cloud-ru/ds-icons/interface/system';
|
|
3
|
+
import { InfoBlock } from '@cloud-ru/ds-info-block';
|
|
4
|
+
import { ProgressBar } from '@cloud-ru/ds-progress-bar';
|
|
5
|
+
import { SkeletonText } from '@cloud-ru/ds-skeleton';
|
|
6
|
+
import { Tooltip } from '@cloud-ru/ds-tooltip';
|
|
7
|
+
import { TruncateString } from '@cloud-ru/ds-truncate-string';
|
|
8
|
+
import { Typography } from '@cloud-ru/ds-typography';
|
|
9
|
+
import { WithSupportProps } from '@cloud-ru/ds-utils';
|
|
10
|
+
|
|
11
|
+
import { quotaLocale } from '../../locale';
|
|
12
|
+
import { QuotaItem } from '../../types';
|
|
13
|
+
import { checkIsExceeded, formatNumber, getPercent } from '../../utils';
|
|
14
|
+
import { QuotaTooltip } from './components/QuotaTooltip';
|
|
15
|
+
import styles from './styles.module.scss';
|
|
16
|
+
|
|
17
|
+
export type QuotaWidgetCardProps = WithSupportProps<{
|
|
18
|
+
/** Отображаемая квота */
|
|
19
|
+
quota: QuotaItem;
|
|
20
|
+
/** Состояние «не удалось загрузить данные» (Figma: noData=true) */
|
|
21
|
+
noData?: boolean;
|
|
22
|
+
/** Состояние загрузки (Figma: loading=true) */
|
|
23
|
+
loading?: boolean;
|
|
24
|
+
/** Колбек кнопки «Обновить» в состоянии noData */
|
|
25
|
+
onRefresh?: () => void;
|
|
26
|
+
}>;
|
|
27
|
+
|
|
28
|
+
const QUOTA_USAGE_PROGRESS = {
|
|
29
|
+
HIGH: 90,
|
|
30
|
+
MEDIUM: 70,
|
|
31
|
+
} as const;
|
|
32
|
+
|
|
33
|
+
function getProgressAppearance(percent: number) {
|
|
34
|
+
if (percent >= QUOTA_USAGE_PROGRESS.HIGH) {
|
|
35
|
+
return 'red';
|
|
36
|
+
}
|
|
37
|
+
if (percent >= QUOTA_USAGE_PROGRESS.MEDIUM) {
|
|
38
|
+
return 'yellow';
|
|
39
|
+
}
|
|
40
|
+
return 'green';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function QuotaWidgetCard({ quota, noData = false, loading = false, onRefresh, ...props }: QuotaWidgetCardProps) {
|
|
44
|
+
const { t } = quotaLocale.useTranslations();
|
|
45
|
+
|
|
46
|
+
if (noData) {
|
|
47
|
+
return (
|
|
48
|
+
<div className={styles.card} data-no-data {...props}>
|
|
49
|
+
<InfoBlock
|
|
50
|
+
size='s'
|
|
51
|
+
align='vertical'
|
|
52
|
+
title={quota.name}
|
|
53
|
+
content={t('errorText')}
|
|
54
|
+
footer={
|
|
55
|
+
onRefresh ? (
|
|
56
|
+
<Button
|
|
57
|
+
view='simple'
|
|
58
|
+
appearance='neutral'
|
|
59
|
+
size='s'
|
|
60
|
+
label={t('errorButton')}
|
|
61
|
+
icon={<UpdateSVG size={16} />}
|
|
62
|
+
iconPosition='after'
|
|
63
|
+
onClick={onRefresh}
|
|
64
|
+
/>
|
|
65
|
+
) : undefined
|
|
66
|
+
}
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (loading) {
|
|
73
|
+
return (
|
|
74
|
+
<div className={styles.card} data-loading {...props}>
|
|
75
|
+
<SkeletonText loading lines={1} variant='body' size='m' />
|
|
76
|
+
<SkeletonText loading lines={1} variant='body' size='m' />
|
|
77
|
+
<SkeletonText loading lines={1} variant='body' size='l' />
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const percent = getPercent(quota);
|
|
83
|
+
|
|
84
|
+
const rows = [
|
|
85
|
+
{
|
|
86
|
+
label: t('cardAvailable'),
|
|
87
|
+
value: quota.limit,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
label: t('cardRemaining'),
|
|
91
|
+
value: quota.remains,
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<Tooltip triggerClassName={styles.tooltip} hoverDelayOpen={500} tip={<QuotaTooltip quota={quota} />}>
|
|
97
|
+
<div className={styles.card} data-exhausted={checkIsExceeded(quota)} {...props}>
|
|
98
|
+
<div className={styles.header}>
|
|
99
|
+
<Typography variant='body' size='m' className={styles.title}>
|
|
100
|
+
<TruncateString maxLines={2} text={quota.name} />
|
|
101
|
+
</Typography>
|
|
102
|
+
|
|
103
|
+
<span className={styles.percent}>{Math.round(percent)}%</span>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<ProgressBar
|
|
107
|
+
className={styles.progressBar}
|
|
108
|
+
progress={percent}
|
|
109
|
+
size='xs'
|
|
110
|
+
appearance={getProgressAppearance(percent)}
|
|
111
|
+
/>
|
|
112
|
+
|
|
113
|
+
<div className={styles.info}>
|
|
114
|
+
{rows.map(row => (
|
|
115
|
+
<div className={styles.row} key={row.label}>
|
|
116
|
+
<span className={styles.label}>{row.label}</span>
|
|
117
|
+
|
|
118
|
+
<span className={styles.value}>
|
|
119
|
+
{formatNumber(row.value)} <span className={styles.unit}>{quota.unitDisplayName}</span>
|
|
120
|
+
</span>
|
|
121
|
+
</div>
|
|
122
|
+
))}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</Tooltip>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { APPEARANCE, Divider } from '@cloud-ru/ds-divider';
|
|
2
|
+
import { Typography } from '@cloud-ru/ds-typography';
|
|
3
|
+
|
|
4
|
+
import { TEST_IDS } from '../../../../constants';
|
|
5
|
+
import { quotaLocale } from '../../../../locale';
|
|
6
|
+
import { QuotaItem } from '../../../../types';
|
|
7
|
+
import { checkIsExceeded, formatNumber } from '../../../../utils';
|
|
8
|
+
import styles from './styles.module.scss';
|
|
9
|
+
|
|
10
|
+
type QuotaTooltipProps = {
|
|
11
|
+
quota: QuotaItem;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function QuotaTooltip({ quota }: QuotaTooltipProps) {
|
|
15
|
+
const { t } = quotaLocale.useTranslations();
|
|
16
|
+
|
|
17
|
+
const rows = [
|
|
18
|
+
{ label: t('tooltipAvailable'), value: quota.limit },
|
|
19
|
+
{ label: t('tooltipUsed'), value: quota.usage },
|
|
20
|
+
{ label: t('tooltipRemaining'), value: quota.remains },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const exhaustedHint = `${t('tooltipExhaustedHint.first')} ${t('tooltipExhaustedHint.second')}`;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className={styles.content} data-test-id={TEST_IDS.quotaWidgetCard.tooltip}>
|
|
27
|
+
<div className={styles.lists}>
|
|
28
|
+
{rows.map(row => (
|
|
29
|
+
<div className={styles.row} key={row.label}>
|
|
30
|
+
<span className={styles.rowLabel}>{row.label}</span>
|
|
31
|
+
<span className={styles.rowValue}>
|
|
32
|
+
{formatNumber(row.value)} {quota.unitDisplayName}
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
{checkIsExceeded(quota) && (
|
|
39
|
+
<>
|
|
40
|
+
<Divider appearance={APPEARANCE.InvertNeutral} />
|
|
41
|
+
<Typography variant='body' size='m'>
|
|
42
|
+
{exhaustedHint}
|
|
43
|
+
</Typography>
|
|
44
|
+
</>
|
|
45
|
+
)}
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './QuotaTooltip';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
|
|
3
|
+
.content {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
row-gap: base.$sn-primitive-dimension-4;
|
|
7
|
+
align-items: stretch;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.lists {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
row-gap: base.$sn-primitive-dimension-4;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.row {
|
|
17
|
+
display: flex;
|
|
18
|
+
column-gap: base.$sn-primitive-dimension-8;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: space-between;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.rowLabel,
|
|
24
|
+
.rowValue {
|
|
25
|
+
@include base.composite-var(base.$base-styles, 'sn', 'regular', 'body', 'm');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.rowValue {
|
|
29
|
+
text-align: right;
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './QuotaWidgetCard';
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/card.module' as card;
|
|
3
|
+
|
|
4
|
+
/* Обёртка триггера тултипа — грид-элемент вместо самой карточки, поэтому она обязана
|
|
5
|
+
отдавать карточке всю ширину трека, а не сжиматься по контенту. */
|
|
6
|
+
.tooltip {
|
|
7
|
+
display: flex;
|
|
8
|
+
width: 100%;
|
|
9
|
+
max-width: 100%;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* figma-selected-block: quotaCard root (node 2921:16397) */
|
|
13
|
+
.card {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex: 1 1 auto;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
row-gap: base.$sn-primitive-dimension-4;
|
|
18
|
+
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
|
|
21
|
+
/* Ширину карточки задаёт трек грида: desktop 2 колонки, mobile 1 колонка — на всю ширину.
|
|
22
|
+
Своей ширины у карточки нет, только нижняя граница (в Figma-мастере карточка 288px).
|
|
23
|
+
`min()` снимает эту границу, когда контейнер уже неё, — узкий лист не переполняется. */
|
|
24
|
+
min-width: min(256px, 100%);
|
|
25
|
+
max-width: 100%;
|
|
26
|
+
padding: base.$sn-primitive-dimension-8;
|
|
27
|
+
border-radius: card.$sn-card-anatomy-radius-s-container-borderRadius;
|
|
28
|
+
|
|
29
|
+
background-color: base.$sn-theme-color-neutral-decorTransparent;
|
|
30
|
+
backdrop-filter: blur(calc(base.$sn-acrylic-blurBackground1Level / 2));
|
|
31
|
+
|
|
32
|
+
&[data-exhausted='true'] {
|
|
33
|
+
background-color: base.simple-var(base.$sn-theme, 'color', 'red', 'background');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* figma-selected-block: title row */
|
|
38
|
+
.header {
|
|
39
|
+
display: flex;
|
|
40
|
+
gap: base.$sn-primitive-dimension-8;
|
|
41
|
+
align-items: flex-end;
|
|
42
|
+
justify-content: space-between;
|
|
43
|
+
|
|
44
|
+
width: 100%;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.title {
|
|
48
|
+
flex: 1 1 0;
|
|
49
|
+
min-width: 0;
|
|
50
|
+
color: base.$sn-theme-color-available-version-textMain;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.percent {
|
|
54
|
+
@include base.composite-var(base.$base-styles, 'sn', 'thin', 'label', 'm');
|
|
55
|
+
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
color: base.$sn-theme-color-available-version-textTertiary;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.progressBar {
|
|
61
|
+
width: 100%;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.info {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
row-gap: base.$sn-primitive-dimension-2;
|
|
68
|
+
width: 100%;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.row {
|
|
72
|
+
display: flex;
|
|
73
|
+
column-gap: base.$sn-primitive-dimension-8;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: space-between;
|
|
76
|
+
|
|
77
|
+
width: 100%;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.label {
|
|
81
|
+
@include base.composite-var(base.$base-styles, 'sn', 'thin', 'label', 's');
|
|
82
|
+
|
|
83
|
+
color: base.$sn-theme-color-available-version-textTertiary;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.value {
|
|
87
|
+
@include base.composite-var(base.$base-styles, 'sn', 'thin', 'label', 'l');
|
|
88
|
+
|
|
89
|
+
color: base.$sn-theme-color-available-version-textMain;
|
|
90
|
+
white-space: nowrap;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.unit {
|
|
94
|
+
@include base.composite-var(base.$base-styles, 'sn', 'thin', 'label', 'l');
|
|
95
|
+
|
|
96
|
+
color: base.$sn-theme-color-available-version-textTertiary;
|
|
97
|
+
}
|