dxd-style-code 0.1.11 → 0.1.13

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 (148) hide show
  1. package/dist/dxd-style-code.js +7470 -6336
  2. package/dist/dxd-style-code.umd.cjs +3 -3
  3. package/dist/style.css +1 -1
  4. package/package.json +2 -2
  5. package/src/components/atoms/DX/DX.stories.js +265 -0
  6. package/src/components/atoms/DX/DX.vue +80 -0
  7. package/src/components/atoms/DX/index.js +2 -0
  8. package/src/components/atoms/DXAvatar/DXAvatar.stories.js +1 -2
  9. package/src/components/atoms/DXBackdrop/DXBackdrop.stories.js +77 -1
  10. package/src/components/atoms/DXBadge/DXBadge.stories.js +83 -1
  11. package/src/components/atoms/DXBlockquote/DXBlockquote.stories.js +67 -1
  12. package/src/components/atoms/DXBox/DXBox.stories.js +1 -1
  13. package/src/components/atoms/DXBox/DXBox.vue +69 -2
  14. package/src/components/atoms/DXButton/DXButton.stories.js +94 -1
  15. package/src/components/atoms/DXButton/DXButton.vue +145 -11
  16. package/src/components/atoms/DXCard/DXCard.stories.js +72 -14
  17. package/src/components/atoms/DXCard/DXCard.vue +3 -4
  18. package/src/components/atoms/DXCheckbox/DXCheckbox.stories.js +85 -1
  19. package/src/components/atoms/DXCode/DXCode.stories.js +67 -1
  20. package/src/components/atoms/DXContainer/DXContainer.stories.js +1 -1
  21. package/src/components/atoms/DXContainer/DXContainer.vue +28 -1
  22. package/src/components/atoms/DXDivider/DXDivider.stories.js +84 -1
  23. package/src/components/atoms/DXFlex/DXFlex.stories.js +1 -1
  24. package/src/components/atoms/DXFlex/DXFlex.vue +57 -3
  25. package/src/components/atoms/DXFormLabel/DXFormLabel.stories.js +70 -1
  26. package/src/components/atoms/DXGrid/DXGrid.stories.js +1 -1
  27. package/src/components/atoms/DXHeading/DXHeading.stories.js +90 -1
  28. package/src/components/atoms/DXIcon/DXIcon.stories.js +74 -0
  29. package/src/components/atoms/DXIconWrapper/DXIconWrapper.stories.js +69 -0
  30. package/src/components/atoms/DXImage/DXImage.stories.js +483 -0
  31. package/src/components/atoms/DXImage/DXImage.vue +294 -0
  32. package/src/components/atoms/DXImage/index.js +2 -0
  33. package/src/components/atoms/DXInputAddon/DXInputAddon.stories.js +86 -1
  34. package/src/components/atoms/DXLabel/DXLabel.stories.js +62 -1
  35. package/src/components/atoms/DXLink/DXLink.stories.js +75 -10
  36. package/src/components/atoms/DXLink/DXLink.vue +59 -3
  37. package/src/components/atoms/DXList/DXList.stories.js +76 -1
  38. package/src/components/atoms/DXLoader/DXLoader.stories.js +75 -1
  39. package/src/components/atoms/DXNav/DXNav.stories.js +236 -0
  40. package/src/components/atoms/DXNav/DXNav.vue +114 -0
  41. package/src/components/atoms/DXNav/index.js +2 -0
  42. package/src/components/atoms/DXProgress/DXProgress.stories.js +76 -1
  43. package/src/components/atoms/DXRadio/DXRadio.stories.js +85 -1
  44. package/src/components/atoms/DXSkeleton/DXSkeleton.stories.js +59 -1
  45. package/src/components/atoms/DXSlider/DXSlider.stories.js +89 -0
  46. package/src/components/atoms/DXSpacer/DXSpacer.stories.js +1 -1
  47. package/src/components/atoms/DXStack/DXStack.stories.js +1 -1
  48. package/src/components/atoms/DXStack/DXStack.vue +5 -2
  49. package/src/components/atoms/DXTags/DXTags.stories.js +77 -0
  50. package/src/components/atoms/DXText/DXText.stories.js +83 -1
  51. package/src/components/atoms/DXToast/DXToast.stories.js +64 -1
  52. package/src/components/atoms/DXToggle/DXToggle.stories.js +84 -1
  53. package/src/components/atoms/DXToggleButton/DXToggleButton.stories.js +78 -1
  54. package/src/components/atoms/DXTooltip/DXTooltip.stories.js +98 -1
  55. package/src/components/atoms/index.js +3 -0
  56. package/src/components/molecules/DXActionButtons/DXActionButtons.stories.js +280 -77
  57. package/src/components/molecules/DXActionButtons/DXActionButtons.vue +31 -31
  58. package/src/components/molecules/DXAlert/DXAlert.stories.js +199 -1
  59. package/src/components/molecules/DXAlert/DXAlert.vue +35 -13
  60. package/src/components/molecules/DXBreadcrumb/DXBreadcrumb.stories.js +125 -1
  61. package/src/components/molecules/DXBreadcrumb/DXBreadcrumb.vue +22 -18
  62. package/src/components/molecules/DXButtonGroup/DXButtonGroup.stories.js +193 -6
  63. package/src/components/molecules/DXButtonGroup/DXButtonGroup.vue +39 -3
  64. package/src/components/molecules/DXCloseButton/DXCloseButton.stories.js +64 -1
  65. package/src/components/molecules/DXComboBox/DXComboBox.stories.js +66 -0
  66. package/src/components/molecules/DXCopyField/DXCopyField.stories.js +128 -1
  67. package/src/components/molecules/DXCopyField/DXCopyField.vue +60 -7
  68. package/src/components/molecules/DXDataFilter/DXDataFilter.vue +8 -6
  69. package/src/components/molecules/DXDatePicker/DXDatePicker.stories.js +58 -0
  70. package/src/components/molecules/DXFileUpload/DXFileUpload.stories.js +66 -0
  71. package/src/components/molecules/DXFilterGroup/DXFilterGroup.stories.js +61 -0
  72. package/src/components/molecules/DXFormControl/DXFormControl.stories.js +76 -0
  73. package/src/components/molecules/DXFormControl/DXFormControl.vue +9 -8
  74. package/src/components/molecules/DXInput/DXInput.stories.js +100 -1
  75. package/src/components/molecules/DXInputGroup/DXInputGroup.stories.js +89 -1
  76. package/src/components/molecules/DXInputMask/DXInputMask.stories.js +67 -0
  77. package/src/components/molecules/DXMenu/DXMenu.stories.js +111 -4
  78. package/src/components/molecules/DXMenu/DXMenu.vue +18 -5
  79. package/src/components/molecules/DXMenu/README.md +1 -1
  80. package/src/components/molecules/DXPagination/DXPagination.stories.js +105 -2
  81. package/src/components/molecules/DXPagination/DXPagination.vue +18 -33
  82. package/src/components/molecules/DXPasswordInput/DXPasswordInput.stories.js +67 -1
  83. package/src/components/molecules/DXRadioCard/DXRadioCard.stories.js +64 -0
  84. package/src/components/molecules/DXRadioGroup/DXRadioGroup.stories.js +84 -0
  85. package/src/components/molecules/DXRating/DXRating.stories.js +3 -2
  86. package/src/components/molecules/DXSearchBar/DXSearchBar.stories.js +1 -1
  87. package/src/components/molecules/DXSearchBar/DXSearchBar.vue +16 -12
  88. package/src/components/molecules/DXSearchSelect/DXSearchSelect.stories.js +71 -0
  89. package/src/components/molecules/DXSegmentedControl/DXSegmentedControl.stories.js +74 -0
  90. package/src/components/molecules/DXSelect/DXSelect.stories.js +92 -1
  91. package/src/components/molecules/DXStatCard/DXStatCard.stories.js +1 -1
  92. package/src/components/molecules/DXStatCard/DXStatCard.vue +30 -26
  93. package/src/components/molecules/DXTableFiltersPanel/index.js +3 -0
  94. package/src/components/molecules/DXTablePagination/DXTablePagination.stories.js +67 -0
  95. package/src/components/molecules/DXTableToolbar/DXTableToolbar.stories.js +71 -0
  96. package/src/components/molecules/DXTextarea/DXTextarea.stories.js +87 -1
  97. package/src/components/molecules/DXTimePicker/DXTimePicker.stories.js +1 -1
  98. package/src/components/molecules/DXValidationIcon/DXValidationIcon.stories.js +59 -1
  99. package/src/components/molecules/index.js +0 -1
  100. package/src/components/organisms/DXAccordion/DXAccordion.stories.js +75 -0
  101. package/src/components/organisms/DXAppLayout/DXAppLayout.stories.js +27 -25
  102. package/src/components/organisms/DXAuthenticationForm/DXAuthenticationForm.stories.js +0 -2
  103. package/src/components/organisms/DXAuthenticationForm/DXAuthenticationForm.vue +5 -8
  104. package/src/components/{molecules → organisms}/DXBaseTable/DXBaseTable.stories.js +78 -1
  105. package/src/components/{molecules → organisms}/DXBaseTable/DXBaseTable.vue +2 -2
  106. package/src/components/organisms/DXChartContainer/DXChartContainer.stories.js +1 -1
  107. package/src/components/organisms/DXChartContainer/DXChartContainer.vue +10 -6
  108. package/src/components/organisms/DXChatInterface/DXChatInterface.stories.js +1 -1
  109. package/src/components/organisms/DXChatInterface/DXChatInterface.vue +6 -4
  110. package/src/components/organisms/DXCommentSection/DXCommentSection.stories.js +1 -1
  111. package/src/components/organisms/DXCommentSection/DXCommentSection.vue +7 -6
  112. package/src/components/organisms/DXDashboardGrid/DXDashboardGrid.stories.js +1 -1
  113. package/src/components/organisms/DXDashboardGrid/DXDashboardGrid.vue +4 -2
  114. package/src/components/organisms/DXDashboardWidget/DXDashboardWidget.stories.js +1 -1
  115. package/src/components/organisms/DXDashboardWidget/DXDashboardWidget.vue +3 -2
  116. package/src/components/organisms/DXDataTable/DXDataTable.stories.js +1 -1
  117. package/src/components/organisms/DXDropdown/DXDropdown.stories.js +84 -1
  118. package/src/components/organisms/DXEmptyState/DXEmptyState.stories.js +64 -0
  119. package/src/components/organisms/DXEmptyState/DXEmptyState.vue +4 -2
  120. package/src/components/organisms/DXHeaderBar/DXHeaderBar.stories.js +409 -3
  121. package/src/components/organisms/DXHeaderBar/DXHeaderBar.vue +261 -52
  122. package/src/components/organisms/DXMediaGallery/DXMediaGallery.stories.js +1 -1
  123. package/src/components/organisms/DXMediaGallery/DXMediaGallery.vue +6 -4
  124. package/src/components/organisms/DXModal/DXModal.stories.js +93 -1
  125. package/src/components/organisms/DXModal/DXModal.vue +3 -2
  126. package/src/components/organisms/DXNotificationCenter/DXNotificationCenter.stories.js +1 -1
  127. package/src/components/organisms/DXNotificationCenter/DXNotificationCenter.vue +2 -1
  128. package/src/components/organisms/DXReportGenerator/DXReportGenerator.vue +4 -3
  129. package/src/components/organisms/DXSettingsPanel/DXSettingsPanel.vue +11 -8
  130. package/src/components/organisms/DXSidebar/DXSidebar.stories.js +1 -1
  131. package/src/components/organisms/DXSidebarMenu/DXSidebarMenu.stories.js +104 -1
  132. package/src/components/organisms/DXSidebarMenu/DXSidebarMenu.vue +14 -4
  133. package/src/components/organisms/DXSidebarMenu/README.md +3 -3
  134. package/src/components/organisms/DXTable/DXTable.stories.js +138 -11
  135. package/src/components/organisms/DXTable/DXTable.vue +1 -1
  136. package/src/components/organisms/DXTabs/DXTabs.stories.js +91 -1
  137. package/src/components/organisms/DXUserProfileCard/DXUserProfileCard.stories.js +1 -1
  138. package/src/components/organisms/DXUserProfileCard/DXUserProfileCard.vue +20 -18
  139. package/src/components/organisms/index.js +1 -0
  140. package/src/components/utilities/DXAnimatePresence/DXAnimatePresence.stories.js +1 -1
  141. package/src/components/utilities/DXBreakpointProvider/DXBreakpointProvider.stories.js +1 -1
  142. package/src/components/utilities/DXObserver/DXObserver.stories.js +1 -1
  143. package/src/components/utilities/DXPortal/DXPortal.stories.js +1 -1
  144. package/src/components/utilities/DXStaggeredAnimation/DXStaggeredAnimation.stories.js +2 -2
  145. package/src/components/utilities/DXThemeProvider/DXThemeProvider.stories.js +1 -1
  146. package/src/components/utilities/DXTransitionGroup/DXTransitionGroup.stories.js +1 -1
  147. package/src/composables/useSize.js +8 -1
  148. /package/src/components/{molecules → organisms}/DXBaseTable/index.js +0 -0
@@ -4,99 +4,134 @@
4
4
  data-component="DXHeaderBar"
5
5
  :data-sticky="sticky"
6
6
  :data-fixed="fixed"
7
+ :data-variant="variant || 'default'"
8
+ :data-breakpoint="currentBreakpoint?.value || null"
9
+ :data-mobile="isMobile"
7
10
  >
8
- <DXContainer :size="containerSize" :padding="containerPadding">
9
- <div class="flex items-center justify-between gap-4 h-full">
11
+ <DXContainer :size="containerSize" :padding="containerPadding" position="relative">
12
+ <DXFlex justify="between" align="center" gap="md" height="full">
10
13
  <!-- Логотип и название -->
11
- <div class="flex items-center gap-3 flex-shrink-0">
14
+ <DXFlex align="center" gap="sm" :shrink="true">
12
15
  <DXLink
13
16
  v-if="logo || appName"
14
17
  :to="logoLink"
15
18
  :href="logoHref"
16
19
  variant="ghost"
17
- class="flex items-center gap-3 hover:opacity-80 transition-opacity"
18
20
  >
19
- <img
20
- v-if="logo"
21
- :src="logo"
22
- :alt="appName || 'Logo'"
23
- class="h-8 w-auto object-contain"
24
- />
25
- <h1 v-if="appName" class="text-lg font-semibold text-slate-900">
26
- {{ appName }}
27
- </h1>
21
+ <DXFlex align="center" gap="sm">
22
+ <DXImage
23
+ v-if="logo"
24
+ :src="logo"
25
+ :alt="appName || 'Logo'"
26
+ height="32"
27
+ object-fit="contain"
28
+ />
29
+ <DXHeading v-if="appName" level="1" size="lg" weight="semibold">
30
+ {{ appName }}
31
+ </DXHeading>
32
+ </DXFlex>
28
33
  </DXLink>
29
34
  <slot name="logo" />
30
- </div>
35
+ </DXFlex>
31
36
 
32
37
  <!-- Навигация (desktop) -->
33
- <nav
38
+ <DXNav
34
39
  v-if="$slots.navigation"
40
+ type="main"
35
41
  class="hidden md:flex items-center gap-1 flex-1"
36
42
  >
37
43
  <slot name="navigation" />
38
- </nav>
44
+ </DXNav>
39
45
 
40
46
  <!-- Поиск (desktop) -->
41
- <div
47
+ <DXFlex
42
48
  v-if="$slots.search"
43
- class="hidden md:flex items-center flex-1 max-w-md mx-4"
49
+ align="center"
50
+ class="hidden md:flex flex-1 max-w-md mx-4"
44
51
  >
45
52
  <slot name="search" />
46
- </div>
53
+ </DXFlex>
47
54
 
48
55
  <!-- Действия (desktop) -->
49
- <div
56
+ <DXFlex
50
57
  v-if="$slots.actions"
51
- class="hidden md:flex items-center gap-2 flex-shrink-0"
58
+ align="center"
59
+ gap="sm"
60
+ :shrink="true"
61
+ class="hidden md:flex"
52
62
  >
53
63
  <slot name="actions" />
54
- </div>
64
+ </DXFlex>
55
65
 
56
66
  <!-- Мобильное меню -->
57
- <div class="flex md:hidden items-center gap-2">
67
+ <DXFlex align="center" gap="sm" class="md:hidden">
58
68
  <slot name="mobile-menu" />
59
- </div>
69
+ </DXFlex>
70
+ </DXFlex>
71
+
72
+ <!-- Центральная часть - абсолютное позиционирование -->
73
+ <div
74
+ v-if="$slots.center"
75
+ class="hidden md:block absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"
76
+ >
77
+ <slot name="center" />
60
78
  </div>
61
79
  </DXContainer>
62
80
 
63
81
  <!-- Мобильная навигация (drawer) -->
64
- <Transition v-if="showMobileMenu && $slots['mobile-navigation']">
65
- <div
66
- class="md:hidden fixed inset-0 z-50 bg-white"
67
- :class="mobileMenuClasses"
82
+ <DXAnimatePresence
83
+ v-if="$slots['mobile-navigation']"
84
+ :show="showMobileMenu"
85
+ type="slide-down"
86
+ mode="default"
87
+ >
88
+ <DXBox
89
+ position="fixed"
90
+ inset
91
+ z-index="50"
92
+ bg="white"
93
+ :class="['md:hidden', mobileMenuClasses]"
68
94
  >
69
- <div class="p-4">
70
- <div class="flex items-center justify-between mb-4">
71
- <h2 v-if="appName" class="text-lg font-semibold text-slate-900">
72
- {{ appName }}
73
- </h2>
74
- <DXButton
75
- variant="ghost"
76
- size="sm"
77
- @click="closeMobileMenu"
78
- >
79
- <template #icon>
80
- <DXIcon :icon="XMarkIcon" size="md" />
81
- </template>
82
- </DXButton>
83
- </div>
84
- <nav class="space-y-2">
95
+ <DXBox p="md">
96
+ <DXBox my="md">
97
+ <DXFlex justify="between" align="center">
98
+ <DXHeading v-if="appName" level="2" size="lg" weight="semibold">
99
+ {{ appName }}
100
+ </DXHeading>
101
+ <DXButton
102
+ variant="ghost"
103
+ size="sm"
104
+ @click="closeMobileMenu"
105
+ >
106
+ <template #icon>
107
+ <DXIcon :icon="XMarkIcon" size="md" />
108
+ </template>
109
+ </DXButton>
110
+ </DXFlex>
111
+ </DXBox>
112
+ <DXStack tag="nav" gap="sm" direction="vertical">
85
113
  <slot name="mobile-navigation" />
86
- </nav>
87
- </div>
88
- </div>
89
- </Transition>
114
+ </DXStack>
115
+ </DXBox>
116
+ </DXBox>
117
+ </DXAnimatePresence>
90
118
  </header>
91
119
  </template>
92
120
 
93
121
  <script setup>
94
- import { ref, computed } from "vue";
122
+ import { ref, computed, inject } from "vue";
95
123
  import { useClassComposition } from "../../../composables/useClassComposition";
96
124
  import DXContainer from "../../atoms/DXContainer/DXContainer.vue";
125
+ import DXFlex from "../../atoms/DXFlex/DXFlex.vue";
126
+ import DXBox from "../../atoms/DXBox/DXBox.vue";
127
+ import DXStack from "../../atoms/DXStack/DXStack.vue";
128
+ import DXImage from "../../atoms/DXImage/DXImage.vue";
129
+ import DXHeading from "../../atoms/DXHeading/DXHeading.vue";
97
130
  import DXLink from "../../atoms/DXLink/DXLink.vue";
98
131
  import DXButton from "../../atoms/DXButton/DXButton.vue";
99
132
  import DXIcon from "../../atoms/DXIcon/DXIcon.vue";
133
+ import DXNav from "../../atoms/DXNav/DXNav.vue";
134
+ import DXAnimatePresence from "../../utilities/DXAnimatePresence/DXAnimatePresence.vue";
100
135
  import { XMarkIcon } from "@heroicons/vue/24/outline";
101
136
 
102
137
  const props = defineProps({
@@ -118,24 +153,191 @@ const props = defineProps({
118
153
  containerPadding: { type: String, default: "md" },
119
154
  /** Высота header */
120
155
  height: { type: String, default: "auto", validator: (v) => ["auto", "sm", "md", "lg"].includes(v) },
156
+ /** Вариант стилизации: bordered | elevated | flat */
157
+ variant: {
158
+ type: String,
159
+ default: null,
160
+ validator: (value) => value === null || ['bordered', 'elevated', 'flat'].includes(value),
161
+ },
162
+ /** Фон: white | slate | transparent */
163
+ bg: {
164
+ type: String,
165
+ default: "white",
166
+ validator: (value) => ['white', 'slate', 'transparent'].includes(value),
167
+ },
168
+ /** Тень: none | sm | md | lg | xl */
169
+ shadow: {
170
+ type: String,
171
+ default: null,
172
+ validator: (value) => value === null || ['none', 'sm', 'md', 'lg', 'xl'].includes(value),
173
+ },
174
+ /** Рамка: none | bottom | full */
175
+ border: {
176
+ type: String,
177
+ default: "bottom",
178
+ validator: (value) => ['none', 'bottom', 'full'].includes(value),
179
+ },
121
180
  });
122
181
 
123
182
  const emit = defineEmits(["mobile-menu-toggle"]);
124
183
 
184
+ // Получение данных о breakpoint через inject (если DXBreakpointProvider доступен)
185
+ const currentBreakpoint = inject('currentBreakpoint', ref(null));
186
+ const screenWidth = inject('screenWidth', ref(null));
187
+ const screenHeight = inject('screenHeight', ref(null));
188
+ const breakpoints = inject('breakpoints', ref(null));
189
+
190
+ // Состояние мобильного меню
125
191
  const showMobileMenu = ref(false);
126
192
 
193
+ /**
194
+ * Проверка, является ли текущий breakpoint мобильным
195
+ *
196
+ * @description
197
+ * Определяет, находится ли приложение в мобильном режиме на основе breakpoint.
198
+ *
199
+ * @returns {boolean} true если breakpoint меньше md (768px)
200
+ */
201
+ const isMobile = computed(() => {
202
+ if (!currentBreakpoint?.value) {
203
+ // Fallback: проверка через screenWidth если breakpoint недоступен
204
+ if (screenWidth?.value !== null && screenWidth?.value !== undefined) {
205
+ return screenWidth.value < 768;
206
+ }
207
+ return false;
208
+ }
209
+
210
+ // Считаем мобильным если breakpoint меньше md
211
+ const mobileBreakpoints = ['xs', 'sm'];
212
+ return mobileBreakpoints.includes(currentBreakpoint.value);
213
+ });
214
+
215
+ /**
216
+ * Проверка, является ли текущий breakpoint десктопным
217
+ *
218
+ * @description
219
+ * Определяет, находится ли приложение в десктопном режиме.
220
+ *
221
+ * @returns {boolean} true если breakpoint >= md (768px)
222
+ */
223
+ const isDesktop = computed(() => !isMobile.value);
224
+
225
+ /**
226
+ * Классы фона
227
+ *
228
+ * @description
229
+ * Определяет классы для background-color в зависимости от значения bg prop.
230
+ *
231
+ * @returns {string} Tailwind CSS класс для фона
232
+ */
233
+ const bgClass = computed(() => {
234
+ const bgClasses = {
235
+ white: "bg-white",
236
+ slate: "bg-slate-50",
237
+ transparent: "bg-transparent",
238
+ };
239
+
240
+ return bgClasses[props.bg] || "bg-white";
241
+ });
242
+
243
+ /**
244
+ * Классы тени
245
+ *
246
+ * @description
247
+ * Определяет классы для box-shadow в зависимости от значения shadow prop.
248
+ *
249
+ * @returns {string|null} Tailwind CSS класс для тени или null
250
+ */
251
+ const shadowClass = computed(() => {
252
+ if (!props.shadow) return null;
253
+
254
+ const shadowClasses = {
255
+ none: "shadow-none",
256
+ sm: "shadow-sm",
257
+ md: "shadow",
258
+ lg: "shadow-lg",
259
+ xl: "shadow-xl",
260
+ };
261
+
262
+ return shadowClasses[props.shadow] || null;
263
+ });
264
+
265
+ /**
266
+ * Классы рамки
267
+ *
268
+ * @description
269
+ * Определяет классы для border в зависимости от значения border prop.
270
+ *
271
+ * @returns {string|null} Tailwind CSS класс для рамки или null
272
+ */
273
+ const borderClass = computed(() => {
274
+ if (props.border === "none") return null;
275
+
276
+ const borderClasses = {
277
+ bottom: "border-b border-slate-200",
278
+ full: "border border-slate-200",
279
+ };
280
+
281
+ return borderClasses[props.border] || "border-b border-slate-200";
282
+ });
283
+
284
+ /**
285
+ * Классы варианта стилизации
286
+ *
287
+ * @description
288
+ * Определяет дополнительные классы в зависимости от варианта стилизации.
289
+ *
290
+ * @returns {string|null} Дополнительные классы или null
291
+ */
292
+ const variantClass = computed(() => {
293
+ if (!props.variant) return null;
294
+
295
+ const variantClasses = {
296
+ bordered: "border-slate-300",
297
+ elevated: null, // Тень применяется через shadow prop
298
+ flat: "border-0",
299
+ };
300
+
301
+ return variantClasses[props.variant] || null;
302
+ });
303
+
304
+ /**
305
+ * Финальная тень (с учетом variant)
306
+ *
307
+ * @description
308
+ * Если variant="elevated" и shadow не указан, применяется shadow-sm по умолчанию.
309
+ * Иначе используется значение shadow prop.
310
+ *
311
+ * @returns {string|null} Tailwind CSS класс для тени или null
312
+ */
313
+ const finalShadowClass = computed(() => {
314
+ if (props.shadow) {
315
+ return shadowClass.value;
316
+ }
317
+
318
+ if (props.variant === "elevated") {
319
+ return "shadow-sm";
320
+ }
321
+
322
+ return null;
323
+ });
324
+
127
325
  /**
128
326
  * Классы для header
129
327
  *
130
328
  * @description
131
329
  * Вычисляет классы для header компонента, включая позиционирование (sticky/fixed),
132
- * высоту и фон.
330
+ * высоту, фон, тень, рамку и вариант стилизации.
133
331
  *
134
332
  * @returns {Array} Массив классов для header
135
333
  */
136
334
  const headerClasses = computed(() =>
137
335
  useClassComposition(
138
- "w-full bg-white border-b border-slate-200",
336
+ "w-full",
337
+ bgClass.value,
338
+ finalShadowClass.value,
339
+ borderClass.value,
340
+ variantClass.value,
139
341
  {
140
342
  "sticky top-0 z-40": props.sticky && !props.fixed,
141
343
  "fixed top-0 left-0 right-0 z-40": props.fixed,
@@ -180,11 +382,18 @@ function openMobileMenu() {
180
382
  emit("mobile-menu-toggle", true);
181
383
  }
182
384
 
183
- // Экспортируем методы для использования в родительском компоненте
385
+ // Экспортируем методы и данные для использования в родительском компоненте
184
386
  defineExpose({
185
387
  openMobileMenu,
186
388
  closeMobileMenu,
187
389
  showMobileMenu,
390
+ // Breakpoint данные (если доступны через DXBreakpointProvider)
391
+ currentBreakpoint,
392
+ screenWidth,
393
+ screenHeight,
394
+ breakpoints,
395
+ isMobile,
396
+ isDesktop,
188
397
  });
189
398
  </script>
190
399
 
@@ -50,7 +50,7 @@ const defaultItems = [
50
50
  export default {
51
51
  title: 'Organisms/DXMediaGallery',
52
52
  component: DXMediaGallery,
53
- tags: ['autodocs'],
53
+ tags: ['autodocs', 'category:data-display'],
54
54
  parameters: {
55
55
  docs: {
56
56
  description: {
@@ -128,12 +128,12 @@
128
128
  autoplay
129
129
  />
130
130
  <div v-if="selectedItem.title || selectedItem.description" class="mt-4">
131
- <h3 v-if="selectedItem.title" class="text-lg font-semibold text-slate-900">
131
+ <DXHeading v-if="selectedItem.title" level="3" size="lg" weight="semibold" color="default">
132
132
  {{ selectedItem.title }}
133
- </h3>
134
- <p v-if="selectedItem.description" class="text-sm text-slate-600 mt-1">
133
+ </DXHeading>
134
+ <DXText v-if="selectedItem.description" tag="p" size="sm" color="muted" class="mt-1">
135
135
  {{ selectedItem.description }}
136
- </p>
136
+ </DXText>
137
137
  </div>
138
138
  </div>
139
139
 
@@ -175,6 +175,8 @@ import DXModal from "../DXModal/DXModal.vue";
175
175
  import DXObserver from "../../utilities/DXObserver/DXObserver.vue";
176
176
  import DXButton from "../../atoms/DXButton/DXButton.vue";
177
177
  import DXIcon from "../../atoms/DXIcon/DXIcon.vue";
178
+ import DXHeading from "../../atoms/DXHeading/DXHeading.vue";
179
+ import DXText from "../../atoms/DXText/DXText.vue";
178
180
  import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/vue/24/outline";
179
181
 
180
182
  const props = defineProps({
@@ -5,7 +5,99 @@ import DXButton from '../../atoms/DXButton/DXButton.vue';
5
5
  export default {
6
6
  title: 'Organisms/DXModal',
7
7
  component: DXModal,
8
- tags: ['autodocs'],
8
+ tags: ['autodocs', 'category:overlay'],
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component: `
13
+ # DXModal
14
+
15
+ Универсальный компонент модального окна с поддержкой различных вариантов отображения и режимов.
16
+
17
+ ## Назначение
18
+
19
+ DXModal предоставляет полнофункциональное модальное окно с поддержкой различных вариантов отображения
20
+ (модальное окно, полноэкранный режим, боковая панель, половина экрана справа), настраиваемым backdrop,
21
+ переключателем режимов и слотами для кастомизации контента.
22
+
23
+ ## Архитектура
24
+
25
+ ### Использует
26
+ - \`DXBackdrop\` - фон модального окна с размытием и блокировкой скролла
27
+ - \`DXCloseButton\` - кнопка закрытия
28
+ - \`DXHeading\` - заголовок модального окна
29
+ - \`Transition\` - анимации появления/исчезновения
30
+
31
+ ### Используется в
32
+ - Формы редактирования
33
+ - Диалоги подтверждения
34
+ - Детальные просмотры
35
+ - Настройки и конфигурация
36
+ - Любые места, требующие фокусированного взаимодействия
37
+
38
+ ## Внутренняя логика
39
+
40
+ ### Варианты отображения
41
+ - **modal** (по умолчанию): Классическое модальное окно по центру экрана с настраиваемой шириной
42
+ - **fullscreen**: Полноэкранный режим, занимает весь экран
43
+ - **sidebar-right**: Боковая панель справа, выезжает с правой стороны
44
+ - **half-right**: Половина экрана справа, фиксированная позиция
45
+
46
+ ### Анимации
47
+ - **modal/fullscreen**: Использует анимацию \`fade-scale\` (появление с масштабированием)
48
+ - **sidebar-right/half-right**: Использует анимацию \`slide-right\` (выезд справа)
49
+
50
+ ### Управление состоянием
51
+ - Управляется через \`open\` prop (Boolean)
52
+ - События: \`close\`, \`opened\`, \`closed\`
53
+ - Поддержка \`update:variant\` для динамического изменения режима
54
+
55
+ ### Backdrop
56
+ - Настраиваемое размытие: \`none\`, \`sm\`, \`md\`, \`lg\`, \`xl\`
57
+ - Настраиваемая прозрачность (0-100)
58
+ - Настраиваемый цвет: \`slate-900\`, \`gray-900\`, \`black\`, \`white\`
59
+ - Блокировка скролла body (по умолчанию включена)
60
+ - Возможность закрытия по клику на backdrop (через \`closable\`)
61
+
62
+ ### Переключатель режимов
63
+ При \`showModeSwitcher={true}\` отображается переключатель режимов в заголовке:
64
+ - Иконки для каждого режима
65
+ - Визуальное выделение текущего режима
66
+ - Событие \`update:variant\` при смене режима
67
+
68
+ ## Особенности
69
+
70
+ ### Слоты
71
+ - **default** - основной контент модального окна
72
+ - **title** - заголовок (по умолчанию "Диалог")
73
+ - **actions** - кнопки действий внизу модального окна
74
+
75
+ ### Ширина (для modal)
76
+ Поддерживает 4 размера ширины:
77
+ - **sm** - маленькая ширина
78
+ - **md** - средняя ширина (по умолчанию)
79
+ - **lg** - большая ширина
80
+ - **xl** - очень большая ширина
81
+
82
+ ### Закрытие
83
+ - Кнопка закрытия в заголовке (если \`closable={true}\`)
84
+ - Закрытие по клику на backdrop (если \`closable={true}\`)
85
+ - Событие \`close\` для программного закрытия
86
+
87
+ ### Структура контента
88
+ Модальное окно имеет три секции:
89
+ 1. **Заголовок** - заголовок, переключатель режимов (опционально), кнопка закрытия
90
+ 2. **Контент** - основной контент с прокруткой
91
+ 3. **Действия** - кнопки действий (если используется слот \`actions\`)
92
+
93
+ ### Специальные варианты
94
+ - **half-right**: Не использует backdrop, фиксированная позиция справа, z-index 20
95
+ - **sidebar-right**: Backdrop с z-index 50, выезжает справа
96
+ - **fullscreen**: Занимает весь экран, padding 8
97
+ `,
98
+ },
99
+ },
100
+ },
9
101
  argTypes: {
10
102
  variant: {
11
103
  control: 'select',
@@ -18,9 +18,9 @@
18
18
  >
19
19
  <div :class="containerClass">
20
20
  <div class="flex items-center justify-between flex-shrink-0 mb-4 gap-4">
21
- <h3 class="text-lg font-semibold tracking-tight text-slate-900 flex-1">
21
+ <DXHeading level="3" size="lg" weight="semibold" color="default" class="flex-1">
22
22
  <slot name="title">Диалог</slot>
23
- </h3>
23
+ </DXHeading>
24
24
 
25
25
  <!-- View Mode Switcher -->
26
26
  <div v-if="showModeSwitcher" class="flex items-center gap-1 rounded-xl border border-slate-200 bg-slate-50 p-1">
@@ -68,6 +68,7 @@ import {
68
68
  } from "@heroicons/vue/24/outline";
69
69
  import DXBackdrop from "../../atoms/DXBackdrop/DXBackdrop.vue";
70
70
  import DXCloseButton from "../../molecules/DXCloseButton/DXCloseButton.vue";
71
+ import DXHeading from "../../atoms/DXHeading/DXHeading.vue";
71
72
 
72
73
  const props = defineProps({
73
74
  /** Открыто/закрыто */
@@ -4,7 +4,7 @@ import DXNotificationCenter from './DXNotificationCenter.vue';
4
4
  export default {
5
5
  title: 'Organisms/DXNotificationCenter',
6
6
  component: DXNotificationCenter,
7
- tags: ['autodocs'],
7
+ tags: ['autodocs', 'category:feedback'],
8
8
  parameters: {
9
9
  docs: {
10
10
  description: {
@@ -29,7 +29,7 @@
29
29
  <div v-if="showHeader || $slots.header" :class="headerClasses">
30
30
  <slot name="header">
31
31
  <div class="flex items-center justify-between">
32
- <h3 class="text-lg font-semibold text-slate-900">Уведомления</h3>
32
+ <DXHeading level="3" size="lg" weight="semibold" color="default">Уведомления</DXHeading>
33
33
  <DXButton
34
34
  v-if="unreadCount > 0"
35
35
  size="sm"
@@ -144,6 +144,7 @@ import { useSpacing } from "../../../composables/useSpacing";
144
144
  import DXButton from "../../atoms/DXButton/DXButton.vue";
145
145
  import DXIcon from "../../atoms/DXIcon/DXIcon.vue";
146
146
  import DXBadge from "../../atoms/DXBadge/DXBadge.vue";
147
+ import DXHeading from "../../atoms/DXHeading/DXHeading.vue";
147
148
  import DXDropdown from "../DXDropdown/DXDropdown.vue";
148
149
  import {
149
150
  BellIcon,
@@ -6,7 +6,7 @@
6
6
  <!-- Header -->
7
7
  <div v-if="showHeader || $slots.header" :class="headerClasses">
8
8
  <slot name="header">
9
- <h2 class="text-2xl font-bold text-slate-900">Генератор отчетов</h2>
9
+ <DXHeading level="2" size="2xl" weight="bold" color="default">Генератор отчетов</DXHeading>
10
10
  </slot>
11
11
  </div>
12
12
 
@@ -26,7 +26,7 @@
26
26
  <div v-if="$slots.settings || showSettings" :class="settingsClasses">
27
27
  <slot name="settings" :settings="reportSettings" :update-setting="updateSetting">
28
28
  <DXCard v-if="showSettings" class="p-4">
29
- <h3 class="font-semibold mb-4">Настройки отчета</h3>
29
+ <DXHeading level="3" weight="semibold" class="mb-4">Настройки отчета</DXHeading>
30
30
  <div class="space-y-4">
31
31
  <DXFormControl label="Формат экспорта">
32
32
  <DXSelect
@@ -49,7 +49,7 @@
49
49
  <div v-if="$slots.preview || showPreview" :class="previewClasses">
50
50
  <slot name="preview" :data="previewData" :columns="columns">
51
51
  <DXCard v-if="showPreview" class="p-4">
52
- <h3 class="font-semibold mb-4">Предпросмотр</h3>
52
+ <DXHeading level="3" weight="semibold" class="mb-4">Предпросмотр</DXHeading>
53
53
  <DXTable
54
54
  :columns="columns"
55
55
  :data="previewData"
@@ -91,6 +91,7 @@ import { useClassComposition } from "../../../composables/useClassComposition";
91
91
  import { useSpacing } from "../../../composables/useSpacing";
92
92
  import DXCard from "../../atoms/DXCard/DXCard.vue";
93
93
  import DXButton from "../../atoms/DXButton/DXButton.vue";
94
+ import DXHeading from "../../atoms/DXHeading/DXHeading.vue";
94
95
  import DXTable from "../DXTable/DXTable.vue";
95
96
  import DXDataFilter from "../../molecules/DXDataFilter/DXDataFilter.vue";
96
97
  import DXSelect from "../../molecules/DXSelect/DXSelect.vue";