@bethinkpl/design-system 30.3.2 → 30.4.2

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 (73) hide show
  1. package/dist/design-system.css +1 -1
  2. package/dist/design-system.js +5682 -5362
  3. package/dist/design-system.js.map +1 -1
  4. package/dist/i18n/en/globals.json +2 -1
  5. package/dist/i18n/en/statsLayout.json +12 -0
  6. package/dist/i18n/pl/globals.json +2 -1
  7. package/dist/i18n/pl/statsLayout.json +12 -0
  8. package/dist/lib/js/components/Buttons/HelpButton/HelpButton.vue.d.ts +3 -0
  9. package/dist/lib/js/components/Buttons/IconButton/IconButton.vue.d.ts +2 -0
  10. package/dist/lib/js/components/Cards/CardExpandable/CardExpandable.vue.d.ts +2 -0
  11. package/dist/lib/js/components/Chip/Chip.vue.d.ts +4 -0
  12. package/dist/lib/js/components/DatePickers/DateBox/DateBox.vue.d.ts +2 -0
  13. package/dist/lib/js/components/DatePickers/DatePicker/DatePicker.vue.d.ts +2 -0
  14. package/dist/lib/js/components/DatePickers/DateRangePicker/DateRangePicker.vue.d.ts +2 -0
  15. package/dist/lib/js/components/Drawer/DrawerHeader/DrawerHeader.vue.d.ts +8 -0
  16. package/dist/lib/js/components/Drawer/DrawerListItem/DrawerListItem.vue.d.ts +2 -0
  17. package/dist/lib/js/components/Drawer/DrawerSection/DrawerSection.vue.d.ts +6 -0
  18. package/dist/lib/js/components/Form/RadioButton/RadioButton.vue.d.ts +2 -0
  19. package/dist/lib/js/components/Headers/OverlayHeader/OverlayHeader.vue.d.ts +4 -0
  20. package/dist/lib/js/components/Headers/SectionHeader/SectionHeader.vue.d.ts +4 -0
  21. package/dist/lib/js/components/Icons/Icon/Icon.consts.d.ts +2 -0
  22. package/dist/lib/js/components/Modal/Modal.vue.d.ts +2 -0
  23. package/dist/lib/js/components/Modals/Modal/Modal.vue.d.ts +4 -0
  24. package/dist/lib/js/components/Modals/ModalDialog/ModalDialog.vue.d.ts +4 -0
  25. package/dist/lib/js/components/Outline/OutlineItem/OutlineItem.vue.d.ts +2 -0
  26. package/dist/lib/js/components/Pagination/Pagination.vue.d.ts +6 -0
  27. package/dist/lib/js/components/ProgressBar/ProgressBar.vue.d.ts +2 -0
  28. package/dist/lib/js/components/ProgressDonutChart/ProgressDonutChart.vue.d.ts +2 -0
  29. package/dist/lib/js/components/RichList/BasicRichListItem/BasicRichListItem.vue.d.ts +2 -0
  30. package/dist/lib/js/components/RichList/RichListItem/RichListItem.vue.d.ts +2 -0
  31. package/dist/lib/js/components/SelectList/SelectListItem/SelectListItem.vue.d.ts +2 -0
  32. package/dist/lib/js/components/SelectList/SelectListItemToggle/SelectListItemToggle.vue.d.ts +2 -0
  33. package/dist/lib/js/components/SpinnerLoading/SpinnerLoading.vue.d.ts +15 -0
  34. package/dist/lib/js/components/StatsLayout/StatsErrorBanner/StatsErrorBanner.vue.d.ts +6 -0
  35. package/dist/lib/js/components/StatsLayout/StatsFiltersDropdown/StatsFiltersDropdown.vue.d.ts +23 -0
  36. package/dist/lib/js/components/StatsLayout/StatsLayout.vue.d.ts +41 -0
  37. package/dist/lib/js/components/StatsLayout/StatsResetBanner/StatsResetBanner.vue.d.ts +34 -0
  38. package/dist/lib/js/components/StatsLayout/StatsSectionHeader/StatsSectionHeader.vue.d.ts +40 -0
  39. package/dist/lib/js/components/Statuses/AccessStatus/AccessStatus.vue.d.ts +2 -0
  40. package/dist/lib/js/components/Statuses/BlockadeStatus/BlockadeStatus.vue.d.ts +2 -0
  41. package/dist/lib/js/components/SurveyQuestions/SurveyQuestionOpenEnded/SurveyQuestionOpenEnded.vue.d.ts +6 -0
  42. package/dist/lib/js/components/SurveyQuestions/SurveyQuestionScale/SurveyQuestionScale.vue.d.ts +6 -0
  43. package/dist/lib/js/components/Switch/Switch.vue.d.ts +2 -0
  44. package/dist/lib/js/components/Tile/Tile.sb.shared.d.ts +2 -0
  45. package/dist/lib/js/components/Toggles/ToggleButton/ToggleButton.vue.d.ts +2 -0
  46. package/dist/lib/js/i18n/en.d.ts +11 -0
  47. package/dist/lib/js/i18n/index.d.ts +22 -0
  48. package/dist/lib/js/i18n/pl.d.ts +11 -0
  49. package/dist/lib/js/icons/fontawesome.d.ts +2 -0
  50. package/dist/lib/js/index.d.ts +3 -0
  51. package/lib/js/components/Buttons/HelpButton/HelpButton.vue +20 -3
  52. package/lib/js/components/SpinnerLoading/SpinnerLoading.stories.ts +42 -0
  53. package/lib/js/components/SpinnerLoading/SpinnerLoading.vue +33 -0
  54. package/lib/js/components/StatsLayout/StatsErrorBanner/StatsErrorBanner.stories.ts +32 -0
  55. package/lib/js/components/StatsLayout/StatsErrorBanner/StatsErrorBanner.vue +24 -0
  56. package/lib/js/components/StatsLayout/StatsFiltersDropdown/StatsFiltersDropdown.stories.ts +50 -0
  57. package/lib/js/components/StatsLayout/StatsFiltersDropdown/StatsFiltersDropdown.vue +55 -0
  58. package/lib/js/components/StatsLayout/StatsLayout.spec.ts +169 -0
  59. package/lib/js/components/StatsLayout/StatsLayout.stories.ts +156 -0
  60. package/lib/js/components/StatsLayout/StatsLayout.vue +173 -0
  61. package/lib/js/components/StatsLayout/StatsResetBanner/StatsResetBanner.stories.ts +48 -0
  62. package/lib/js/components/StatsLayout/StatsResetBanner/StatsResetBanner.vue +51 -0
  63. package/lib/js/components/StatsLayout/StatsSectionHeader/StatsSectionHeader.stories.ts +68 -0
  64. package/lib/js/components/StatsLayout/StatsSectionHeader/StatsSectionHeader.vue +72 -0
  65. package/lib/js/i18n/en/globals.json +2 -1
  66. package/lib/js/i18n/en/statsLayout.json +12 -0
  67. package/lib/js/i18n/en.ts +2 -0
  68. package/lib/js/i18n/pl/globals.json +2 -1
  69. package/lib/js/i18n/pl/statsLayout.json +12 -0
  70. package/lib/js/i18n/pl.ts +2 -0
  71. package/lib/js/icons/fontawesome.ts +5 -1
  72. package/lib/js/index.ts +3 -0
  73. package/package.json +1 -1
@@ -0,0 +1,42 @@
1
+ import { Args, ArgTypes, Meta, StoryObj } from '@storybook/vue3';
2
+ import SpinnerLoading from './SpinnerLoading.vue';
3
+ import type { ComponentProps } from 'vue-component-type-helpers';
4
+
5
+ type SpinnerLoadingProps = ComponentProps<typeof SpinnerLoading>;
6
+
7
+ const meta: Meta<SpinnerLoadingProps> = {
8
+ title: 'Components/SpinnerLoading',
9
+ component: SpinnerLoading,
10
+ render: (args) => {
11
+ return {
12
+ components: { SpinnerLoading },
13
+ setup() {
14
+ return {
15
+ args,
16
+ };
17
+ },
18
+ template: '<spinner-loading v-bind="args" />',
19
+ };
20
+ },
21
+ parameters: {
22
+ design: {
23
+ type: 'figma',
24
+ url: 'https://www.figma.com/design/WeJCbVlnkL9HmEcoBpu5NU/LMS---Specific-Components---Limbo?node-id=108-7632&m=dev',
25
+ },
26
+ },
27
+ };
28
+ export default meta;
29
+
30
+ type Story = StoryObj<SpinnerLoadingProps>;
31
+
32
+ export const Interactive: Story = {
33
+ args: {
34
+ message: '',
35
+ } as Args,
36
+ };
37
+
38
+ Interactive.argTypes = {
39
+ message: {
40
+ control: 'text',
41
+ },
42
+ } as ArgTypes;
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <div class="ds-spinnerLoading">
3
+ <ds-icon :icon="ICONS.FAD_SPINNER_THIRD" :size="ICON_SIZES.SMALL" spinning />
4
+ <div>{{ message || t('ds.globals.loading') }}</div>
5
+ </div>
6
+ </template>
7
+
8
+ <style scoped lang="scss">
9
+ @import '../../../styles/settings/typography/tokens';
10
+ @import '../../../styles/settings/colors/tokens';
11
+ @import '../../../styles/settings/spacings';
12
+
13
+ .ds-spinnerLoading {
14
+ @include text-m-default-regular();
15
+
16
+ align-items: center;
17
+ color: $color-neutral-text;
18
+ display: inline-flex;
19
+ gap: $space-2xs;
20
+ }
21
+ </style>
22
+
23
+ <script setup lang="ts">
24
+ import { ICON_SIZES, ICONS } from '../Icons/Icon/Icon.consts';
25
+ import DsIcon from '../Icons/Icon/Icon.vue';
26
+ import { useLegacyI18n } from '../../composables/useLegacyI18n';
27
+
28
+ const { t } = useLegacyI18n();
29
+
30
+ const { message } = defineProps<{
31
+ message?: string;
32
+ }>();
33
+ </script>
@@ -0,0 +1,32 @@
1
+ import { Meta, StoryObj } from '@storybook/vue3';
2
+ import StatsErrorBanner from './StatsErrorBanner.vue';
3
+ import type { ComponentProps } from 'vue-component-type-helpers';
4
+
5
+ type StatsErrorBannerProps = ComponentProps<typeof StatsErrorBanner>;
6
+
7
+ const meta: Meta<StatsErrorBannerProps> = {
8
+ title: 'Components/StatsLayout/StatsErrorBanner',
9
+ component: StatsErrorBanner,
10
+ render: (args) => {
11
+ return {
12
+ components: { StatsErrorBanner },
13
+ setup() {
14
+ return {
15
+ args,
16
+ };
17
+ },
18
+ template: '<stats-error-banner v-bind="args"></stats-error-banner>',
19
+ };
20
+ },
21
+ parameters: {
22
+ design: {
23
+ type: 'figma',
24
+ url: 'https://www.figma.com/design/izQdYyiBR1GQgFkaOIfIJI/LMS---DS-Components?node-id=14870-10790&m=dev',
25
+ },
26
+ },
27
+ };
28
+ export default meta;
29
+
30
+ type Story = StoryObj<StatsErrorBannerProps>;
31
+
32
+ export const Interactive: Story = {};
@@ -0,0 +1,24 @@
1
+ <template>
2
+ <ds-banner
3
+ :title="t('ds.statsLayout.statsErrorBanner.title')"
4
+ :button-text="t('ds.statsLayout.statsErrorBanner.buttonText')"
5
+ :icon="ICONS.FA_CIRCLE_EXCLAMATION"
6
+ :color="BANNER_COLORS.DANGER"
7
+ @button-clicked="$emit('button-clicked')"
8
+ >
9
+ <template #defaultText> {{ t('ds.statsLayout.statsErrorBanner.message') }} </template>
10
+ </ds-banner>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import { ICONS } from '../../Icons/Icon';
15
+ import { BANNER_COLORS } from '../../Banner/Banner.consts';
16
+ import DsBanner from '../../Banner/Banner.vue';
17
+ import { useLegacyI18n } from '../../../composables/useLegacyI18n';
18
+
19
+ const { t } = useLegacyI18n();
20
+
21
+ defineEmits<{
22
+ (e: 'button-clicked'): void;
23
+ }>();
24
+ </script>
@@ -0,0 +1,50 @@
1
+ import { Args, ArgTypes, Meta, StoryObj } from '@storybook/vue3';
2
+ import StatsFiltersDropdown from './StatsFiltersDropdown.vue';
3
+ import type { ComponentProps } from 'vue-component-type-helpers';
4
+
5
+ type StatsFiltersDropdownProps = ComponentProps<typeof StatsFiltersDropdown>;
6
+
7
+ const meta: Meta<StatsFiltersDropdownProps> = {
8
+ title: 'Components/StatsLayout/StatsFiltersDropdown',
9
+ component: StatsFiltersDropdown,
10
+ render: (args) => {
11
+ return {
12
+ components: { StatsFiltersDropdown },
13
+ setup() {
14
+ return {
15
+ args,
16
+ };
17
+ },
18
+ template: '<stats-filters-dropdown v-bind="args"></stats-filters-dropdown>',
19
+ };
20
+ },
21
+ parameters: {
22
+ design: {
23
+ type: 'figma',
24
+ url: 'https://www.figma.com/design/izQdYyiBR1GQgFkaOIfIJI/LMS---DS-Components?node-id=14870-10787&m=dev',
25
+ },
26
+ },
27
+ };
28
+ export default meta;
29
+
30
+ type Story = StoryObj<StatsFiltersDropdownProps>;
31
+
32
+ export const Interactive: Story = {
33
+ args: {
34
+ filterItems: [
35
+ { key: 'all', label: 'All' },
36
+ { key: 'active', label: 'Active' },
37
+ { key: 'inactive', label: 'Inactive' },
38
+ ],
39
+ selectedFilterKey: 'all',
40
+ } as Args,
41
+ };
42
+
43
+ Interactive.argTypes = {
44
+ filterItems: {
45
+ control: 'object',
46
+ },
47
+ selectedFilterKey: {
48
+ control: 'text',
49
+ },
50
+ } as ArgTypes;
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <ds-dropdown :placement="DROPDOWN_PLACEMENTS.BOTTOM_END">
3
+ <template #reference="{ isOpened }">
4
+ <ds-button
5
+ :icon-left="ICONS.FA_CHART_COLUMN"
6
+ :icon-right="isOpened ? ICONS.FA_ANGLE_UP : ICONS.FA_ANGLE_DOWN"
7
+ :type="BUTTON_TYPES.TEXT"
8
+ >{{ t('ds.statsLayout.filtersDropdown.title') }}</ds-button
9
+ >
10
+ </template>
11
+ <template #default="{ close }">
12
+ <ds-select-list>
13
+ <ds-select-list-item
14
+ v-for="filterItem in filterItems"
15
+ :key="filterItem.key"
16
+ :label="filterItem.label"
17
+ :is-selected="filterItem.key === selectedFilterKey"
18
+ @click="select(filterItem, close)"
19
+ />
20
+ </ds-select-list>
21
+ </template>
22
+ </ds-dropdown>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import DsButton from '../../Buttons/Button';
27
+ import { ICONS } from '../../Icons/Icon/Icon.consts';
28
+ import DsDropdown from '../../Dropdown/Dropdown.vue';
29
+ import DsSelectList from '../../SelectList/SelectList.vue';
30
+ import DsSelectListItem from '../../SelectList/SelectListItem/SelectListItem.vue';
31
+ import { BUTTON_TYPES } from '../../Buttons/Button/Button.consts';
32
+ import { DROPDOWN_PLACEMENTS } from '../../Dropdown/Dropdown.consts';
33
+ import { useLegacyI18n } from '../../../composables/useLegacyI18n';
34
+
35
+ interface FilterItem {
36
+ key: string;
37
+ label: string;
38
+ }
39
+
40
+ export interface StatsFiltersDropdownProps {
41
+ filterItems?: Array<FilterItem>;
42
+ selectedFilterKey?: string | null;
43
+ }
44
+
45
+ const { filterItems = [], selectedFilterKey = null } = defineProps<StatsFiltersDropdownProps>();
46
+
47
+ const emit = defineEmits<{ select: [key: string] }>();
48
+
49
+ const { t } = useLegacyI18n();
50
+
51
+ const select = (filterItem: FilterItem, close: () => void) => {
52
+ emit('select', filterItem.key);
53
+ close();
54
+ };
55
+ </script>
@@ -0,0 +1,169 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ComponentMountingOptions, mount } from '@vue/test-utils';
3
+ import { h } from 'vue';
4
+
5
+ import StatsLayout from './StatsLayout.vue';
6
+
7
+ describe('StatsLayout', () => {
8
+ const createComponent = (options: ComponentMountingOptions<typeof StatsLayout> = {}) => {
9
+ return mount(StatsLayout, options);
10
+ };
11
+
12
+ it('should create', () => {
13
+ const component = createComponent();
14
+
15
+ expect(component.exists()).toBe(true);
16
+ });
17
+
18
+ it('should render main layout class', () => {
19
+ const component = createComponent();
20
+
21
+ expect(component.find('.ds-statsLayout').exists()).toBe(true);
22
+ });
23
+
24
+ describe('slots', () => {
25
+ it('should render dynamic statsItem slots', () => {
26
+ const component = createComponent({
27
+ slots: {
28
+ 'statsItem-0': () => [h('div', { class: 'test-item-0' }, 'Item 0')],
29
+ 'statsItem-1': () => [h('div', { class: 'test-item-1' }, 'Item 1')],
30
+ 'statsItem-2': () => [h('div', { class: 'test-item-2' }, 'Item 2')],
31
+ },
32
+ });
33
+
34
+ expect(component.find('.test-item-0').exists()).toBe(true);
35
+ expect(component.find('.test-item-1').exists()).toBe(true);
36
+ expect(component.find('.test-item-2').exists()).toBe(true);
37
+ });
38
+
39
+ it('should render dividers between statsItems', () => {
40
+ const component = createComponent({
41
+ slots: {
42
+ 'statsItem-0': () => [h('div', 'Item 0')],
43
+ 'statsItem-1': () => [h('div', 'Item 1')],
44
+ },
45
+ });
46
+
47
+ const dividers = component.findAll('.ds-statsLayout__statsDivider');
48
+ expect(dividers.length).toBe(2);
49
+ });
50
+ });
51
+
52
+ describe('props', () => {
53
+ describe('hasGridHeader', () => {
54
+ it('should render grid headers by default', () => {
55
+ const component = createComponent();
56
+
57
+ const gridHeaders = component.findAll('.ds-statsLayout__gridHeader');
58
+ expect(gridHeaders.length).toBe(2);
59
+ });
60
+
61
+ it('should not render grid headers when hasGridHeader is false', () => {
62
+ const component = createComponent({
63
+ props: {
64
+ hasGridHeader: false,
65
+ },
66
+ });
67
+
68
+ const gridHeaders = component.findAll('.ds-statsLayout__gridHeader');
69
+ expect(gridHeaders.length).toBe(0);
70
+ });
71
+ });
72
+
73
+ describe('hasRightColumn', () => {
74
+ it('should render right column by default', () => {
75
+ const component = createComponent();
76
+
77
+ const rightColumns = component.findAll('.ds-statsLayout__gridHeaderRightColumn');
78
+ expect(rightColumns.length).toBeGreaterThan(0);
79
+ });
80
+
81
+ it('should not render right column when hasRightColumn is false', () => {
82
+ const component = createComponent({
83
+ props: {
84
+ hasRightColumn: false,
85
+ },
86
+ });
87
+
88
+ const rightColumns = component.findAll('.ds-statsLayout__gridHeaderRightColumn');
89
+ expect(rightColumns.length).toBe(0);
90
+ });
91
+ });
92
+
93
+ describe('isLoading', () => {
94
+ it('should not show loading state by default', () => {
95
+ const component = createComponent();
96
+
97
+ expect(component.find('.ds-statsLayout__loading').exists()).toBe(false);
98
+ });
99
+
100
+ it('should show loading state when isLoading is true', () => {
101
+ const component = createComponent({
102
+ props: {
103
+ isLoading: true,
104
+ },
105
+ });
106
+
107
+ expect(component.find('.ds-statsLayout__loading').exists()).toBe(true);
108
+ });
109
+
110
+ it('should hide content when loading', () => {
111
+ const component = createComponent({
112
+ props: {
113
+ isLoading: true,
114
+ },
115
+ slots: {
116
+ overallStatsItem: () => [h('div', { class: 'test-content' }, 'Content')],
117
+ },
118
+ });
119
+
120
+ expect(component.find('.ds-statsLayout__content').exists()).toBe(false);
121
+ expect(component.find('.test-content').exists()).toBe(false);
122
+ });
123
+ });
124
+
125
+ describe('hasError', () => {
126
+ it('should not show error state by default', () => {
127
+ const component = createComponent();
128
+
129
+ expect(component.find('.ds-statsLayout__error').exists()).toBe(false);
130
+ });
131
+
132
+ it('should show error state when hasError is true', () => {
133
+ const component = createComponent({
134
+ props: {
135
+ hasError: true,
136
+ },
137
+ });
138
+
139
+ expect(component.find('.ds-statsLayout__error').exists()).toBe(true);
140
+ });
141
+
142
+ it('should hide content when error', () => {
143
+ const component = createComponent({
144
+ props: {
145
+ hasError: true,
146
+ },
147
+ slots: {
148
+ overallStatsItem: () => [h('div', { class: 'test-content' }, 'Content')],
149
+ },
150
+ });
151
+
152
+ expect(component.find('.ds-statsLayout__content').exists()).toBe(false);
153
+ expect(component.find('.test-content').exists()).toBe(false);
154
+ });
155
+
156
+ it('should prioritize loading over error', () => {
157
+ const component = createComponent({
158
+ props: {
159
+ isLoading: true,
160
+ hasError: true,
161
+ },
162
+ });
163
+
164
+ expect(component.find('.ds-statsLayout__loading').exists()).toBe(true);
165
+ expect(component.find('.ds-statsLayout__error').exists()).toBe(false);
166
+ });
167
+ });
168
+ });
169
+ });
@@ -0,0 +1,156 @@
1
+ import { Args, ArgTypes, Meta, StoryObj } from '@storybook/vue3';
2
+ import StatsLayout from './StatsLayout.vue';
3
+ import type { ComponentProps } from 'vue-component-type-helpers';
4
+ import StatsSectionHeader from './StatsSectionHeader/StatsSectionHeader.vue';
5
+ import StatsResetBanner from './StatsResetBanner/StatsResetBanner.vue';
6
+ import SlotPlaceholder from '../../../../.storybook/SlotPlaceholder/SlotPlaceholder.vue';
7
+
8
+ type StatsLayoutProps = ComponentProps<typeof StatsLayout>;
9
+
10
+ const prepareItemsTemplate = (
11
+ itemsCount: number = 5,
12
+ itemTemplate: string = '<slot-placeholder/>',
13
+ ) => {
14
+ return Array.from({ length: itemsCount }, (_, index) => {
15
+ return `<template v-slot:["statsItem-${index}"]>${itemTemplate}</template>`;
16
+ }).join('');
17
+ };
18
+
19
+ const meta: Meta<StatsLayoutProps> = {
20
+ title: 'Components/StatsLayout/StatsLayout',
21
+ component: StatsLayout,
22
+ render: (args) => {
23
+ return {
24
+ components: { StatsLayout, SlotPlaceholder },
25
+ setup() {
26
+ return { args };
27
+ },
28
+ template: `
29
+ <stats-layout v-bind="args">
30
+ <template #sectionHeader>
31
+ <slot-placeholder label="Slot nagłówka sekcji" />
32
+ </template>
33
+ <template #overallStatsItem><slot-placeholder /></template>
34
+ <template #resetBanner>
35
+ <slot-placeholder label="Slot banera resetu" />
36
+ </template>
37
+ ${prepareItemsTemplate()}
38
+ </stats-layout>
39
+ `,
40
+ };
41
+ },
42
+ args: {
43
+ hasGridHeader: true,
44
+ hasRightColumn: true,
45
+ leftColumnLabel: 'Zakres',
46
+ rightColumnLabel: 'Wyniki',
47
+ statsItemsHeaderLabel: '{Nazwa użytej taksonomii}',
48
+ isLoading: false,
49
+ hasError: false,
50
+ } as Args,
51
+ argTypes: {
52
+ hasGridHeader: {
53
+ control: 'boolean',
54
+ },
55
+ hasRightColumn: {
56
+ control: 'boolean',
57
+ },
58
+ leftColumnLabel: {
59
+ control: 'text',
60
+ },
61
+ rightColumnLabel: {
62
+ control: 'text',
63
+ },
64
+ statsItemsHeaderLabel: {
65
+ control: 'text',
66
+ },
67
+ isLoading: {
68
+ control: 'boolean',
69
+ },
70
+ hasError: {
71
+ control: 'boolean',
72
+ },
73
+ } as ArgTypes,
74
+ parameters: {
75
+ design: {
76
+ type: 'figma',
77
+ url: 'https://www.figma.com/design/izQdYyiBR1GQgFkaOIfIJI/LMS---DS-Components?node-id=14877-39964&m=dev',
78
+ },
79
+ },
80
+ };
81
+ export default meta;
82
+
83
+ type Story = StoryObj<StatsLayoutProps>;
84
+
85
+ export const Raw: Story = {};
86
+
87
+ export const WithHeaders: Story = {
88
+ render: (args) => {
89
+ return {
90
+ components: { StatsLayout, StatsSectionHeader, StatsResetBanner, SlotPlaceholder },
91
+ setup() {
92
+ return {
93
+ args,
94
+ filterItems: [
95
+ { key: 'all', label: 'Wszystkie' },
96
+ { key: 'week', label: 'Tydzień' },
97
+ { key: 'month', label: 'Miesiąc' },
98
+ ],
99
+ };
100
+ },
101
+ template: `
102
+ <stats-layout v-bind="args">
103
+ <template #sectionHeader>
104
+ <stats-section-header :filter-items="filterItems" selected-filter-key="all">
105
+ <template #infoModalContent><span>Info content for filter</span></template>
106
+ </stats-section-header>
107
+ </template>
108
+ <template #overallStatsItem><slot-placeholder /></template>
109
+ <template #resetBanner>
110
+ <stats-reset-banner timeMarker="2 czerwca 2025" infoModalTitle="Info modal title">
111
+ <template #infoModalContent><p>Info content for reset banner</p></template>
112
+ </stats-reset-banner>
113
+ </template>
114
+ ${prepareItemsTemplate()}
115
+ </stats-layout>
116
+ `,
117
+ };
118
+ },
119
+ };
120
+
121
+ export const MultipleColumns: Story = {
122
+ render: (args) => {
123
+ const itemTemplate = `<div><slot-placeholder label="Slot left" /></div><div><slot-placeholder label="Slot" /></div>`;
124
+
125
+ return {
126
+ components: { StatsLayout, StatsSectionHeader, StatsResetBanner, SlotPlaceholder },
127
+ setup() {
128
+ return {
129
+ args,
130
+ filterItems: [
131
+ { key: 'all', label: 'Wszystkie' },
132
+ { key: 'week', label: 'Tydzień' },
133
+ { key: 'month', label: 'Miesiąc' },
134
+ ],
135
+ };
136
+ },
137
+ template: `
138
+ <stats-layout v-bind="args">
139
+ <template #sectionHeader>
140
+ <stats-section-header :filter-items="filterItems" selected-filter-key="all">
141
+ <template #infoModalContent><span>Info content for filter</span></template>
142
+ </stats-section-header>
143
+ </template>
144
+ <template #overallStatsItem>
145
+ ${itemTemplate}
146
+ </template>
147
+ <template #resetBanner>
148
+ <stats-reset-banner timeMarker="2 czerwca 2025" infoModalTitle="Info modal title">
149
+ <template #infoModalContent><p>Info content for reset banner</p></template>
150
+ </stats-reset-banner>
151
+ </template>
152
+ ${prepareItemsTemplate(5, itemTemplate)}
153
+ </stats-layout>`,
154
+ };
155
+ },
156
+ };