@dxtmisha/wiki 0.24.3 → 0.25.1

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 (230) hide show
  1. package/package.json +7 -7
  2. package/src/classes/WikiStorybookItem.ts +24 -0
  3. package/src/media/descriptions/wikiDescriptions.ts +28 -0
  4. package/src/media/descriptions/wikiDescriptionsAccordion.ts +158 -0
  5. package/src/media/descriptions/wikiDescriptionsActionSheet.ts +211 -0
  6. package/src/media/descriptions/wikiDescriptionsActions.ts +161 -0
  7. package/src/media/descriptions/wikiDescriptionsAnchor.ts +42 -0
  8. package/src/media/descriptions/wikiDescriptionsArrow.ts +181 -0
  9. package/src/media/descriptions/wikiDescriptionsBlock.ts +97 -0
  10. package/src/media/descriptions/wikiDescriptionsButton.ts +0 -1
  11. package/src/media/descriptions/wikiDescriptionsCell.ts +2 -1
  12. package/src/media/descriptions/wikiDescriptionsChipGroup.ts +168 -0
  13. package/src/media/descriptions/wikiDescriptionsDialog.ts +182 -0
  14. package/src/media/descriptions/wikiDescriptionsField.ts +2 -0
  15. package/src/media/descriptions/wikiDescriptionsImage.ts +41 -6
  16. package/src/media/descriptions/wikiDescriptionsInput.ts +257 -0
  17. package/src/media/descriptions/wikiDescriptionsMenu.ts +123 -0
  18. package/src/media/descriptions/wikiDescriptionsModal.ts +145 -0
  19. package/src/media/descriptions/wikiDescriptionsMotionTransform.ts +2 -6
  20. package/src/media/descriptions/wikiDescriptionsSelect.ts +209 -0
  21. package/src/media/descriptions/wikiDescriptionsSelectValue.ts +78 -0
  22. package/src/media/descriptions/wikiDescriptionsTextareaAutosize.ts +50 -0
  23. package/src/media/descriptions/wikiDescriptionsTooltip.ts +89 -0
  24. package/src/media/functional/en/conversions.mdx +67 -0
  25. package/src/media/functional/en/dataUtils.mdx +25 -0
  26. package/src/media/functional/en/datetimeRef.mdx +1 -1
  27. package/src/media/functional/en/eventRef.mdx +1 -1
  28. package/src/media/functional/en/executionUtils.mdx +58 -0
  29. package/src/media/functional/en/geoFlagRef.mdx +1 -1
  30. package/src/media/functional/en/geoIntlRef.mdx +1 -1
  31. package/src/media/functional/en/geoRef.mdx +2 -2
  32. package/src/media/functional/en/meta.mdx +1206 -0
  33. package/src/media/functional/en/metaManager.mdx +376 -0
  34. package/src/media/functional/en/metaOg.mdx +694 -0
  35. package/src/media/functional/en/metaTwitter.mdx +853 -0
  36. package/src/media/functional/en/reactive.mdx +40 -0
  37. package/src/media/functional/en/refTypes.mdx +1 -1
  38. package/src/media/functional/en/useApiRef.mdx +5 -5
  39. package/src/media/functional/en/useMeta.mdx +431 -0
  40. package/src/media/functional/en/validationUtils.mdx +11 -0
  41. package/src/media/functional/ru/conversions.mdx +67 -0
  42. package/src/media/functional/ru/dataUtils.mdx +25 -0
  43. package/src/media/functional/ru/datetimeRef.mdx +2 -2
  44. package/src/media/functional/ru/eventRef.mdx +1 -1
  45. package/src/media/functional/ru/executionUtils.mdx +58 -0
  46. package/src/media/functional/ru/geoFlagRef.mdx +1 -1
  47. package/src/media/functional/ru/geoIntl.mdx +2 -2
  48. package/src/media/functional/ru/geoIntlRef.mdx +1 -1
  49. package/src/media/functional/ru/geoRef.mdx +2 -2
  50. package/src/media/functional/ru/listTypes.mdx +1 -1
  51. package/src/media/functional/ru/meta.mdx +1330 -0
  52. package/src/media/functional/ru/metaManager.mdx +376 -0
  53. package/src/media/functional/ru/metaOg.mdx +694 -0
  54. package/src/media/functional/ru/metaTwitter.mdx +853 -0
  55. package/src/media/functional/ru/reactive.mdx +40 -0
  56. package/src/media/functional/ru/refTypes.mdx +2 -2
  57. package/src/media/functional/ru/useApiRef.mdx +5 -5
  58. package/src/media/functional/ru/useMeta.mdx +431 -0
  59. package/src/media/functional/ru/validationUtils.mdx +11 -0
  60. package/src/media/mdx/Accordion/accordion.en.mdx +59 -0
  61. package/src/media/mdx/Accordion/accordion.ru.mdx +59 -0
  62. package/src/media/mdx/Accordion/slots.en.mdx +6 -0
  63. package/src/media/mdx/Accordion/slots.ru.mdx +6 -0
  64. package/src/media/mdx/Accordion/wikiMdxAccordion.ts +25 -0
  65. package/src/media/mdx/ActionSheet/actionSheet.en.mdx +61 -0
  66. package/src/media/mdx/ActionSheet/actionSheet.ru.mdx +61 -0
  67. package/src/media/mdx/ActionSheet/touchClose.en.mdx +21 -0
  68. package/src/media/mdx/ActionSheet/touchClose.ru.mdx +21 -0
  69. package/src/media/mdx/ActionSheet/wikiMdxActionSheet.ts +25 -0
  70. package/src/media/mdx/Actions/actions.en.mdx +48 -0
  71. package/src/media/mdx/Actions/actions.ru.mdx +48 -0
  72. package/src/media/mdx/Actions/flexible.en.mdx +19 -0
  73. package/src/media/mdx/Actions/flexible.ru.mdx +19 -0
  74. package/src/media/mdx/Actions/list.en.mdx +50 -0
  75. package/src/media/mdx/Actions/list.ru.mdx +50 -0
  76. package/src/media/mdx/Actions/wikiMdxActions.ts +31 -0
  77. package/src/media/mdx/Anchor/anchor.en.mdx +34 -0
  78. package/src/media/mdx/Anchor/anchor.ru.mdx +34 -0
  79. package/src/media/mdx/Anchor/expose.go.en.mdx +6 -0
  80. package/src/media/mdx/Anchor/expose.go.ru.mdx +6 -0
  81. package/src/media/mdx/Anchor/hide.en.mdx +28 -0
  82. package/src/media/mdx/Anchor/hide.ru.mdx +28 -0
  83. package/src/media/mdx/Anchor/isCopy.en.mdx +23 -0
  84. package/src/media/mdx/Anchor/isCopy.ru.mdx +23 -0
  85. package/src/media/mdx/Anchor/scroll.en.mdx +34 -0
  86. package/src/media/mdx/Anchor/scroll.ru.mdx +35 -0
  87. package/src/media/mdx/Anchor/wikiMdxAnchor.ts +43 -0
  88. package/src/media/mdx/Arrow/arrow.en.mdx +33 -0
  89. package/src/media/mdx/Arrow/arrow.ru.mdx +33 -0
  90. package/src/media/mdx/Arrow/wikiMdxArrow.ts +19 -0
  91. package/src/media/mdx/Block/block.en.mdx +42 -0
  92. package/src/media/mdx/Block/block.ru.mdx +42 -0
  93. package/src/media/mdx/Block/wikiMdxBlock.ts +19 -0
  94. package/src/media/mdx/ChipGroup/chipGroup.en.mdx +51 -0
  95. package/src/media/mdx/ChipGroup/chipGroup.ru.mdx +51 -0
  96. package/src/media/mdx/ChipGroup/selected.en.mdx +50 -0
  97. package/src/media/mdx/ChipGroup/selected.ru.mdx +50 -0
  98. package/src/media/mdx/ChipGroup/wikiMdxChipGroup.ts +25 -0
  99. package/src/media/mdx/Dialog/buttons.en.mdx +45 -0
  100. package/src/media/mdx/Dialog/buttons.ru.mdx +45 -0
  101. package/src/media/mdx/Dialog/dialog.en.mdx +66 -0
  102. package/src/media/mdx/Dialog/dialog.ru.mdx +65 -0
  103. package/src/media/mdx/Dialog/events.en.mdx +63 -0
  104. package/src/media/mdx/Dialog/events.ru.mdx +63 -0
  105. package/src/media/mdx/Dialog/states.en.mdx +58 -0
  106. package/src/media/mdx/Dialog/states.ru.mdx +57 -0
  107. package/src/media/mdx/Dialog/wikiMdxDialog.ts +37 -0
  108. package/src/media/mdx/Field/arrows.en.mdx +22 -6
  109. package/src/media/mdx/Field/arrows.ru.mdx +22 -6
  110. package/src/media/mdx/Field/slots.en.mdx +0 -13
  111. package/src/media/mdx/Field/slots.ru.mdx +0 -13
  112. package/src/media/mdx/Image/img-tag.en.mdx +105 -0
  113. package/src/media/mdx/Image/img-tag.ru.mdx +105 -0
  114. package/src/media/mdx/Image/wikiMdxImage.ts +6 -0
  115. package/src/media/mdx/Input/currency.en.mdx +38 -0
  116. package/src/media/mdx/Input/currency.ru.mdx +38 -0
  117. package/src/media/mdx/Input/date.en.mdx +53 -0
  118. package/src/media/mdx/Input/date.ru.mdx +53 -0
  119. package/src/media/mdx/Input/input.en.mdx +143 -0
  120. package/src/media/mdx/Input/input.ru.mdx +71 -0
  121. package/src/media/mdx/Input/mask.en.mdx +30 -0
  122. package/src/media/mdx/Input/mask.ru.mdx +30 -0
  123. package/src/media/mdx/Input/number.en.mdx +41 -0
  124. package/src/media/mdx/Input/number.ru.mdx +41 -0
  125. package/src/media/mdx/Input/type.en.mdx +26 -0
  126. package/src/media/mdx/Input/type.ru.mdx +26 -0
  127. package/src/media/mdx/Input/wikiMdxInput.ts +49 -0
  128. package/src/media/mdx/Menu/event.updateValue.en.mdx +29 -0
  129. package/src/media/mdx/Menu/event.updateValue.ru.mdx +30 -0
  130. package/src/media/mdx/Menu/expose.navigation.en.mdx +12 -0
  131. package/src/media/mdx/Menu/expose.navigation.ru.mdx +12 -0
  132. package/src/media/mdx/Menu/navigation.en.mdx +56 -0
  133. package/src/media/mdx/Menu/navigation.ru.mdx +56 -0
  134. package/src/media/mdx/Menu/slots.control.en.mdx +65 -0
  135. package/src/media/mdx/Menu/slots.control.ru.mdx +65 -0
  136. package/src/media/mdx/Menu/slots.en.mdx +2 -24
  137. package/src/media/mdx/Menu/slots.ru.mdx +2 -24
  138. package/src/media/mdx/Menu/wikiMdxMenu.ts +27 -3
  139. package/src/media/mdx/Modal/differences.en.mdx +130 -0
  140. package/src/media/mdx/Modal/differences.ru.mdx +65 -0
  141. package/src/media/mdx/Modal/modal.en.mdx +63 -0
  142. package/src/media/mdx/Modal/modal.ru.mdx +63 -0
  143. package/src/media/mdx/Modal/wikiMdxModal.ts +25 -0
  144. package/src/media/mdx/MotionTransform/expose.motionTransformElement.en.mdx +13 -0
  145. package/src/media/mdx/MotionTransform/expose.motionTransformElement.ru.mdx +14 -0
  146. package/src/media/mdx/MotionTransform/wikiMdxMotionTransform.ts +6 -0
  147. package/src/media/mdx/Select/select.en.mdx +69 -0
  148. package/src/media/mdx/Select/select.ru.mdx +69 -0
  149. package/src/media/mdx/Select/wikiMdxSelect.ts +19 -0
  150. package/src/media/mdx/SelectValue/selectValue.en.mdx +64 -0
  151. package/src/media/mdx/SelectValue/selectValue.ru.mdx +64 -0
  152. package/src/media/mdx/SelectValue/wikiMdxSelectValue.ts +19 -0
  153. package/src/media/mdx/TextareaAutosize/textarea-autosize.en.mdx +65 -0
  154. package/src/media/mdx/TextareaAutosize/textarea-autosize.ru.mdx +65 -0
  155. package/src/media/mdx/TextareaAutosize/wikiMdxTextareaAutosize.ts +19 -0
  156. package/src/media/mdx/Tooltip/event.tooltip.en.mdx +7 -0
  157. package/src/media/mdx/Tooltip/event.tooltip.ru.mdx +8 -0
  158. package/src/media/mdx/Tooltip/slot.control.en.mdx +14 -0
  159. package/src/media/mdx/Tooltip/slot.control.ru.mdx +14 -0
  160. package/src/media/mdx/Tooltip/tooltip.en.mdx +34 -0
  161. package/src/media/mdx/Tooltip/tooltip.ru.mdx +34 -0
  162. package/src/media/mdx/Tooltip/wikiMdxTooltip.ts +31 -0
  163. package/src/media/mdx/Window/classes.ru.mdx +1 -1
  164. package/src/media/mdx/event/events.actions.en.mdx +44 -0
  165. package/src/media/mdx/event/events.actions.ru.mdx +44 -0
  166. package/src/media/mdx/event/events.inputStandard.en.mdx +6 -0
  167. package/src/media/mdx/event/events.inputStandard.ru.mdx +6 -0
  168. package/src/media/mdx/event/wikiMdxEvent.ts +20 -8
  169. package/src/media/mdx/expose/expose.descriptionId.en.mdx +6 -0
  170. package/src/media/mdx/expose/expose.descriptionId.ru.mdx +6 -0
  171. package/src/media/mdx/expose/expose.id.en.mdx +6 -0
  172. package/src/media/mdx/expose/expose.id.ru.mdx +6 -0
  173. package/src/media/mdx/expose/expose.labelId.en.mdx +6 -0
  174. package/src/media/mdx/expose/expose.labelId.ru.mdx +6 -0
  175. package/src/media/mdx/expose/wikiMdxExpose.ts +18 -0
  176. package/src/media/mdx/slot/body.en.mdx +6 -0
  177. package/src/media/mdx/slot/body.ru.mdx +6 -0
  178. package/src/media/mdx/slot/headline.en.mdx +7 -0
  179. package/src/media/mdx/slot/headline.ru.mdx +6 -0
  180. package/src/media/mdx/slot/leading.en.mdx +7 -0
  181. package/src/media/mdx/slot/leading.ru.mdx +7 -0
  182. package/src/media/mdx/slot/secondary.en.mdx +5 -0
  183. package/src/media/mdx/slot/secondary.ru.mdx +5 -0
  184. package/src/media/mdx/slot/trailing.en.mdx +7 -0
  185. package/src/media/mdx/slot/trailing.ru.mdx +7 -0
  186. package/src/media/mdx/slot/wikiMdxSlot.ts +30 -0
  187. package/src/media/mdx/style/isSkeleton.en.mdx +2 -2
  188. package/src/media/mdx/style/isSkeleton.ru.mdx +2 -2
  189. package/src/media/mdx/value/v-model-selected.en.mdx +28 -0
  190. package/src/media/mdx/value/v-model-selected.ru.mdx +28 -0
  191. package/src/media/mdx/value/v-model.en.mdx +26 -0
  192. package/src/media/mdx/value/v-model.ru.mdx +26 -0
  193. package/src/media/mdx/value/wikiMdxValue.ts +24 -3
  194. package/src/media/mdx/wikiMdx.ts +29 -1
  195. package/src/media/props/wiki.ts +42 -0
  196. package/src/media/props/wikiActions.ts +43 -0
  197. package/src/media/props/wikiActionsInclude.ts +62 -0
  198. package/src/media/props/wikiAnchor.ts +84 -0
  199. package/src/media/props/wikiAria.ts +102 -0
  200. package/src/media/props/wikiArrow.ts +24 -0
  201. package/src/media/props/wikiArrowInclude.ts +45 -0
  202. package/src/media/props/wikiBarsInclude.ts +80 -0
  203. package/src/media/props/wikiChipGroup.ts +39 -0
  204. package/src/media/props/wikiDialog.ts +34 -0
  205. package/src/media/props/wikiField.ts +0 -21
  206. package/src/media/props/wikiFieldCounterInclude.ts +78 -0
  207. package/src/media/props/wikiForm.ts +248 -0
  208. package/src/media/props/wikiHook.ts +20 -0
  209. package/src/media/props/wikiIcon.ts +3 -3
  210. package/src/media/props/wikiIconInclude.ts +319 -0
  211. package/src/media/props/wikiImage.ts +71 -19
  212. package/src/media/props/wikiInformation.ts +160 -0
  213. package/src/media/props/wikiInput.ts +34 -0
  214. package/src/media/props/wikiListItem.ts +20 -0
  215. package/src/media/props/wikiMask.ts +0 -10
  216. package/src/media/props/wikiMaskInclude.ts +54 -0
  217. package/src/media/props/wikiMenu.ts +0 -10
  218. package/src/media/props/wikiMotionTransform.ts +0 -10
  219. package/src/media/props/wikiOption.ts +113 -0
  220. package/src/media/props/wikiSelect.ts +68 -0
  221. package/src/media/props/wikiSelectValue.ts +30 -0
  222. package/src/media/props/wikiStatus.ts +29 -41
  223. package/src/media/props/wikiStyle.ts +154 -243
  224. package/src/media/props/wikiTechnical.ts +65 -0
  225. package/src/media/props/wikiText.ts +57 -0
  226. package/src/media/props/wikiTooltip.ts +53 -0
  227. package/src/media/props/wikiValue.ts +14 -203
  228. package/src/media/props/wikiWindow.ts +0 -31
  229. package/src/styles/storybookStyle.scss +3 -1
  230. package/src/types/storybookTypes.ts +26 -4
@@ -0,0 +1,1330 @@
1
+ import {Meta} from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title='@dxtmisha/functional/ru/Classes/Meta'/>
4
+
5
+ # Класс Meta
6
+
7
+ Унифицированный класс для управления всеми типами мета-тегов: стандартные HTML, Open Graph и Twitter Card. Предоставляет единый интерфейс для работы с SEO-оптимизацией и социальными сетями, автоматически синхронизируя изменения между всеми платформами.
8
+
9
+ ## Основные возможности
10
+
11
+ - **Унифицированный API** — одна точка входа для всех типов мета-тегов
12
+ - **Автоматическая синхронизация** — изменения в Meta автоматически применяются к Open Graph и Twitter Card
13
+ - **Управление заголовком** — поддержка суффикса для заголовка страницы (например, "Заголовок - Название сайта")
14
+ - **Полная интеграция** — объединяет MetaManager, MetaOg и MetaTwitter
15
+ - **Упрощенный интерфейс** — сокращает количество кода для установки мета-тегов
16
+ - **Поддержка keywords** — работа с ключевыми словами в виде строки или массива
17
+ - **Robots директивы** — управление индексацией и crawling
18
+ - **SSR совместимость** — генерация HTML для серверного рендеринга
19
+
20
+ ## Конструктор
21
+
22
+ ### `constructor`
23
+
24
+ Создает экземпляр Meta с интегрированной поддержкой Open Graph и Twitter Card. Автоматически инициализирует внутренние экземпляры MetaOg и MetaTwitter.
25
+
26
+ ```javascript
27
+ import { Meta } from '@dxtmisha/functional'
28
+
29
+ // Создание единого менеджера мета-тегов
30
+ const meta = new Meta()
31
+
32
+ // Класс автоматически управляет:
33
+ // - Стандартными HTML мета-тегами (description, keywords, author, robots, canonical)
34
+ // - Open Graph тегами (og:title, og:description, og:image, og:url, og:site_name, og:locale)
35
+ // - Twitter Card тегами (twitter:card, twitter:title, twitter:description, twitter:image, twitter:site)
36
+ ```
37
+
38
+ ## Методы получения данных
39
+
40
+ ### `getTitle`
41
+
42
+ Получает заголовок страницы без суффикса.
43
+
44
+ **Возвращает:** `string` — заголовок страницы
45
+
46
+ ```javascript
47
+ const meta = new Meta()
48
+
49
+ // Установить заголовок с суффиксом
50
+ meta.setSuffix('Мой Сайт')
51
+ meta.setTitle('Главная страница')
52
+
53
+ // document.title = "Главная страница - Мой Сайт"
54
+
55
+ // Получить чистый заголовок (без суффикса)
56
+ const title = meta.getTitle()
57
+ // "Главная страница"
58
+
59
+ // Использование в навигации
60
+ const breadcrumb = meta.getTitle()
61
+
62
+ // Проверка наличия
63
+ if (meta.getTitle()) {
64
+ console.log('Заголовок установлен')
65
+ }
66
+ ```
67
+
68
+ ### `getKeywords`
69
+
70
+ Получает мета-тег keywords.
71
+
72
+ **Возвращает:** `string` — ключевые слова через запятую
73
+
74
+ ```javascript
75
+ const meta = new Meta()
76
+
77
+ const keywords = meta.getKeywords()
78
+ // "веб-разработка, javascript, vue, react"
79
+
80
+ // Преобразование в массив
81
+ const keywordsArray = keywords.split(', ')
82
+
83
+ // Проверка наличия ключевого слова
84
+ if (meta.getKeywords().includes('javascript')) {
85
+ console.log('Страница про JavaScript')
86
+ }
87
+
88
+ // Использование для фильтрации
89
+ const tags = meta.getKeywords().split(', ')
90
+ ```
91
+
92
+ ### `getDescription`
93
+
94
+ Получает мета-тег description.
95
+
96
+ **Возвращает:** `string` — описание страницы
97
+
98
+ ```javascript
99
+ const meta = new Meta()
100
+
101
+ const description = meta.getDescription()
102
+ // "Полное руководство по веб-разработке"
103
+
104
+ // Проверка длины
105
+ if (meta.getDescription().length > 160) {
106
+ console.warn('Описание слишком длинное для Google')
107
+ }
108
+
109
+ // Использование в превью
110
+ const preview = meta.getDescription().substring(0, 100)
111
+
112
+ // Для структурированных данных
113
+ const schema = {
114
+ description: meta.getDescription()
115
+ }
116
+ ```
117
+
118
+ ### `getImage`
119
+
120
+ Получает URL изображения Open Graph.
121
+
122
+ **Возвращает:** `string` — URL изображения
123
+
124
+ ```javascript
125
+ const meta = new Meta()
126
+
127
+ const imageUrl = meta.getImage()
128
+ // "https://example.com/images/preview.jpg"
129
+
130
+ // Предзагрузка
131
+ const img = new Image()
132
+ img.src = meta.getImage()
133
+
134
+ // Использование в шаринге
135
+ const shareData = {
136
+ title: meta.getTitle(),
137
+ text: meta.getDescription(),
138
+ image: meta.getImage()
139
+ }
140
+
141
+ // Проверка наличия
142
+ if (!meta.getImage()) {
143
+ console.warn('Изображение для социальных сетей не установлено')
144
+ }
145
+ ```
146
+
147
+ ### `getCanonical`
148
+
149
+ Получает канонический URL.
150
+
151
+ **Возвращает:** `string` — канонический URL
152
+
153
+ ```javascript
154
+ const meta = new Meta()
155
+
156
+ const canonicalUrl = meta.getCanonical()
157
+ // "https://example.com/page"
158
+
159
+ // Проверка совпадения с текущим URL
160
+ if (meta.getCanonical() !== window.location.href) {
161
+ console.log('Canonical URL отличается от текущего')
162
+ }
163
+
164
+ // Использование для редиректов
165
+ const canonical = meta.getCanonical()
166
+
167
+ // Для sitemap
168
+ const url = meta.getCanonical()
169
+ ```
170
+
171
+ ### `getRobots`
172
+
173
+ Получает значение мета-тега robots.
174
+
175
+ **Возвращает:** `MetaRobots` — директива для роботов
176
+
177
+ ```javascript
178
+ const meta = new Meta()
179
+
180
+ const robots = meta.getRobots()
181
+ // "index, follow"
182
+
183
+ // Проверка индексации
184
+ if (meta.getRobots().includes('noindex')) {
185
+ console.log('Страница не должна индексироваться')
186
+ }
187
+
188
+ // Условная логика
189
+ const isIndexable = !meta.getRobots().includes('noindex')
190
+
191
+ // Для отладки
192
+ console.log('Robots directive:', meta.getRobots())
193
+ ```
194
+
195
+ ### `getAuthor`
196
+
197
+ Получает мета-тег author.
198
+
199
+ **Возвращает:** `string` — имя автора
200
+
201
+ ```javascript
202
+ const meta = new Meta()
203
+
204
+ const author = meta.getAuthor()
205
+ // "Иван Иванов"
206
+
207
+ // Отображение информации об авторе
208
+ console.log(`Автор: ${meta.getAuthor()}`)
209
+
210
+ // Для структурированных данных
211
+ const articleSchema = {
212
+ author: {
213
+ name: meta.getAuthor()
214
+ }
215
+ }
216
+
217
+ // Проверка авторства
218
+ if (meta.getAuthor()) {
219
+ console.log('У контента есть автор')
220
+ }
221
+ ```
222
+
223
+ ### `getSiteName`
224
+
225
+ Получает название сайта Open Graph.
226
+
227
+ **Возвращает:** `string` — название сайта
228
+
229
+ ```javascript
230
+ const meta = new Meta()
231
+
232
+ const siteName = meta.getSiteName()
233
+ // "Мой Блог"
234
+
235
+ // Использование в заголовке
236
+ document.title = `${meta.getTitle()} | ${meta.getSiteName()}`
237
+
238
+ // Для брендинга
239
+ const brandName = meta.getSiteName()
240
+
241
+ // В футере
242
+ const footerText = `© 2024 ${meta.getSiteName()}`
243
+ ```
244
+
245
+ ### `getLocale`
246
+
247
+ Получает локаль Open Graph.
248
+
249
+ **Возвращает:** `string` — локаль (например, 'ru_RU')
250
+
251
+ ```javascript
252
+ const meta = new Meta()
253
+
254
+ const locale = meta.getLocale()
255
+ // "ru_RU"
256
+
257
+ // Определение языка
258
+ const language = meta.getLocale().split('_')[0] // "ru"
259
+
260
+ // Использование для i18n
261
+ if (meta.getLocale().startsWith('ru')) {
262
+ console.log('Русскоязычный контент')
263
+ }
264
+
265
+ // Для hreflang
266
+ const lang = meta.getLocale().replace('_', '-').toLowerCase()
267
+ ```
268
+
269
+ ### `getOg`
270
+
271
+ Получает экземпляр MetaOg для расширенных операций с Open Graph.
272
+
273
+ **Возвращает:** `MetaOg` — экземпляр класса MetaOg
274
+
275
+ ```javascript
276
+ const meta = new Meta()
277
+
278
+ // Получить доступ к MetaOg
279
+ const og = meta.getOg()
280
+
281
+ // Использовать специфичные методы Open Graph
282
+ og.setType(MetaOpenGraphType.article)
283
+
284
+ // Доступ ко всем методам MetaOg
285
+ og.getType() // 'article'
286
+
287
+ // Установка дополнительных OG тегов
288
+ meta.getOg().setType(MetaOpenGraphType.video)
289
+
290
+ // Цепочка вызовов
291
+ meta.getOg()
292
+ .setType(MetaOpenGraphType.article)
293
+ .setLocale('ru_RU')
294
+
295
+ // Использование для специфичных настроек
296
+ const setupArticle = () => {
297
+ meta.setTitle('Статья')
298
+ meta.setDescription('Описание')
299
+
300
+ // Специфичные настройки Open Graph
301
+ meta.getOg().setType(MetaOpenGraphType.article)
302
+ }
303
+ ```
304
+
305
+ ### `getTwitter`
306
+
307
+ Получает экземпляр MetaTwitter для расширенных операций с Twitter Card.
308
+
309
+ **Возвращает:** `MetaTwitter` — экземпляр класса MetaTwitter
310
+
311
+ ```javascript
312
+ const meta = new Meta()
313
+
314
+ // Получить доступ к MetaTwitter
315
+ const twitter = meta.getTwitter()
316
+
317
+ // Использовать специфичные методы Twitter Card
318
+ twitter.setCard(MetaTwitterCard.summaryLargeImage)
319
+
320
+ // Доступ ко всем методам MetaTwitter
321
+ twitter.getCard() // 'summary_large_image'
322
+
323
+ // Установка дополнительных Twitter тегов
324
+ meta.getTwitter().setCard(MetaTwitterCard.player)
325
+
326
+ // Цепочка вызовов
327
+ meta.getTwitter()
328
+ .setCard(MetaTwitterCard.summaryLargeImage)
329
+ .setCreator('@author')
330
+
331
+ // Использование для специфичных настроек
332
+ const setupVideo = () => {
333
+ meta.setTitle('Видео')
334
+ meta.setDescription('Описание видео')
335
+
336
+ // Специфичные настройки Twitter Card
337
+ meta.getTwitter().setCard(MetaTwitterCard.player)
338
+ }
339
+
340
+ // Установка creator (не доступен через Meta напрямую)
341
+ meta.getTwitter().setCreator('@john_doe')
342
+ ```
343
+
344
+ ## Методы установки данных
345
+
346
+ ### `setTitle`
347
+
348
+ Устанавливает заголовок страницы с автоматическим добавлением суффикса и обновляет Open Graph и Twitter Card.
349
+
350
+ **Параметры:**
351
+ - `title: string` — заголовок страницы (без суффикса)
352
+
353
+ **Возвращает:** `this` — для цепочечных вызовов
354
+
355
+ ```javascript
356
+ const meta = new Meta()
357
+
358
+ // Установить суффикс (обычно название сайта)
359
+ meta.setSuffix('Мой Сайт')
360
+
361
+ // Установить заголовок
362
+ meta.setTitle('Главная страница')
363
+ // document.title = "Главная страница - Мой Сайт"
364
+ // og:title = "Главная страница - Мой Сайт"
365
+ // twitter:title = "Главная страница - Мой Сайт"
366
+
367
+ // Без суффикса
368
+ const meta2 = new Meta()
369
+ meta2.setTitle('Страница без суффикса')
370
+ // document.title = "Страница без суффикса"
371
+
372
+ // Динамическое обновление
373
+ router.afterEach((to) => {
374
+ meta.setTitle(to.meta.title)
375
+ })
376
+
377
+ // Для разных страниц
378
+ meta.setTitle('О компании')
379
+ meta.setTitle('Контакты')
380
+ meta.setTitle('Блог')
381
+
382
+ // Цепочка вызовов
383
+ meta
384
+ .setTitle('Новая страница')
385
+ .setDescription('Описание страницы')
386
+ ```
387
+
388
+ ### `setKeywords`
389
+
390
+ Устанавливает мета-тег keywords. Принимает строку или массив.
391
+
392
+ **Параметры:**
393
+ - `keywords: string | string[]` — ключевые слова
394
+
395
+ **Возвращает:** `this` — для цепочечных вызовов
396
+
397
+ ```javascript
398
+ const meta = new Meta()
399
+
400
+ // Строка
401
+ meta.setKeywords('веб-разработка, javascript, vue, react')
402
+
403
+ // Массив
404
+ meta.setKeywords(['веб-разработка', 'javascript', 'vue', 'react'])
405
+ // Результат: "веб-разработка, javascript, vue, react"
406
+
407
+ // Из данных страницы
408
+ const page = {
409
+ tags: ['javascript', 'tutorial', 'web']
410
+ }
411
+ meta.setKeywords(page.tags)
412
+
413
+ // Динамическое добавление
414
+ const existingKeywords = meta.getKeywords().split(', ')
415
+ const newKeywords = [...existingKeywords, 'новое', 'ключевое', 'слово']
416
+ meta.setKeywords(newKeywords)
417
+
418
+ // Условное добавление
419
+ const keywords = ['web']
420
+ if (isJavaScriptArticle) {
421
+ keywords.push('javascript')
422
+ }
423
+ meta.setKeywords(keywords)
424
+
425
+ // Примечание: хотя keywords менее важны для SEO,
426
+ // они могут использоваться внутренним поиском
427
+ ```
428
+
429
+ ### `setDescription`
430
+
431
+ Устанавливает мета-тег description.
432
+
433
+ **Параметры:**
434
+ - `description: string` — описание страницы
435
+
436
+ **Возвращает:** `this` — для цепочечных вызовов
437
+
438
+ ```javascript
439
+ const meta = new Meta()
440
+
441
+ // Установка описания
442
+ meta.setDescription('Полное руководство по веб-разработке с примерами кода и практическими заданиями')
443
+
444
+ // Из данных контента
445
+ meta.setDescription(article.excerpt)
446
+
447
+ // Обрезка длинного текста
448
+ const longDescription = article.content
449
+ const shortDescription = longDescription.substring(0, 160)
450
+ meta.setDescription(shortDescription)
451
+
452
+ // Удаление HTML тегов
453
+ const plainText = article.html.replace(/<[^>]*>/g, '')
454
+ meta.setDescription(plainText.substring(0, 160))
455
+
456
+ // Цепочка
457
+ meta
458
+ .setDescription('Описание страницы')
459
+ .setKeywords(['web', 'dev'])
460
+
461
+ // Рекомендации:
462
+ // - Google отображает ~155-160 символов
463
+ // - Yandex отображает ~150-160 символов
464
+ // - Должно содержать ключевые слова
465
+ // - Должно быть уникальным для каждой страницы
466
+ ```
467
+
468
+ ### `setImage`
469
+
470
+ Устанавливает изображение для Open Graph и Twitter Card одновременно.
471
+
472
+ **Параметры:**
473
+ - `image: string` — URL изображения
474
+
475
+ **Возвращает:** `this` — для цепочечных вызовов
476
+
477
+ ```javascript
478
+ const meta = new Meta()
479
+
480
+ // Установка изображения
481
+ meta.setImage('https://example.com/images/preview.jpg')
482
+ // Обновляет og:image и twitter:image
483
+
484
+ // Абсолютный URL
485
+ const imageUrl = new URL('/images/social-preview.jpg', window.location.origin).href
486
+ meta.setImage(imageUrl)
487
+
488
+ // Из данных контента
489
+ meta.setImage(article.coverImage)
490
+
491
+ // Fallback изображение
492
+ meta.setImage(page.image || '/images/default-preview.jpg')
493
+
494
+ // Для разных страниц
495
+ if (isHomePage) {
496
+ meta.setImage('/images/home-preview.jpg')
497
+ } else if (isArticle) {
498
+ meta.setImage(article.image)
499
+ }
500
+
501
+ // Цепочка
502
+ meta
503
+ .setImage('https://example.com/image.jpg')
504
+ .setTitle('Заголовок')
505
+
506
+ // Рекомендуемый размер: 1200x630 px
507
+ // Минимальный размер: 600x315 px
508
+ // Форматы: JPG, PNG, WebP
509
+ ```
510
+
511
+ ### `setCanonical`
512
+
513
+ Устанавливает канонический URL и автоматически обновляет og:url и twitter:url.
514
+
515
+ **Параметры:**
516
+ - `canonical: string` — канонический URL
517
+
518
+ **Возвращает:** `this` — для цепочечных вызовов
519
+
520
+ ```javascript
521
+ const meta = new Meta()
522
+
523
+ // Установка canonical
524
+ meta.setCanonical('https://example.com/page')
525
+ // Обновляет:
526
+ // - <link rel="canonical" href="https://example.com/page">
527
+ // - og:url = "https://example.com/page"
528
+ // - twitter:url = "https://example.com/page"
529
+
530
+ // Текущий URL
531
+ meta.setCanonical(window.location.href)
532
+
533
+ // Очистка параметров
534
+ const cleanUrl = `${window.location.origin}${window.location.pathname}`
535
+ meta.setCanonical(cleanUrl)
536
+
537
+ // Для пагинации (все страницы указывают на первую)
538
+ meta.setCanonical('https://example.com/articles')
539
+
540
+ // Для SPA
541
+ router.afterEach((to) => {
542
+ const url = `https://example.com${to.path}`
543
+ meta.setCanonical(url)
544
+ })
545
+
546
+ // Для дублирующего контента
547
+ meta.setCanonical(originalArticleUrl)
548
+
549
+ // Цепочка
550
+ meta
551
+ .setCanonical('https://example.com/page')
552
+ .setTitle('Заголовок')
553
+ ```
554
+
555
+ ### `setRobots`
556
+
557
+ Устанавливает мета-тег robots для управления индексацией.
558
+
559
+ **Параметры:**
560
+ - `robots: MetaRobots` — директива robots
561
+
562
+ **Возвращает:** `this` — для цепочечных вызовов
563
+
564
+ ```javascript
565
+ import { Meta, MetaRobots } from '@dxtmisha/functional'
566
+
567
+ const meta = new Meta()
568
+
569
+ // Разрешить индексацию (по умолчанию)
570
+ meta.setRobots(MetaRobots.indexFollow)
571
+ // <meta name="robots" content="index, follow">
572
+
573
+ // Запретить индексацию
574
+ meta.setRobots(MetaRobots.noindexNofollow)
575
+ // <meta name="robots" content="noindex, nofollow">
576
+
577
+ // Индексировать, но не следовать по ссылкам
578
+ meta.setRobots(MetaRobots.indexNofollow)
579
+
580
+ // Не индексировать, но следовать по ссылкам
581
+ meta.setRobots(MetaRobots.noindexFollow)
582
+
583
+ // Запретить кэширование
584
+ meta.setRobots(MetaRobots.noarchive)
585
+
586
+ // Не показывать сниппет
587
+ meta.setRobots(MetaRobots.nosnippet)
588
+
589
+ // Условная установка
590
+ if (isDraftPage) {
591
+ meta.setRobots(MetaRobots.noindexNofollow)
592
+ } else {
593
+ meta.setRobots(MetaRobots.indexFollow)
594
+ }
595
+
596
+ // Для закрытых страниц
597
+ meta.setRobots(MetaRobots.noindexNofollow)
598
+
599
+ // Для страниц с дублирующимся контентом
600
+ meta.setRobots(MetaRobots.noindex)
601
+ ```
602
+
603
+ ### `setAuthor`
604
+
605
+ Устанавливает мета-тег author.
606
+
607
+ **Параметры:**
608
+ - `author: string` — имя автора
609
+
610
+ **Возвращает:** `this` — для цепочечных вызовов
611
+
612
+ ```javascript
613
+ const meta = new Meta()
614
+
615
+ // Установка автора
616
+ meta.setAuthor('Иван Иванов')
617
+
618
+ // Из данных пользователя
619
+ meta.setAuthor(article.author.name)
620
+
621
+ // Полное имя
622
+ meta.setAuthor(`${user.firstName} ${user.lastName}`)
623
+
624
+ // Для блога
625
+ meta.setAuthor(post.author)
626
+
627
+ // Условная установка
628
+ if (article.author) {
629
+ meta.setAuthor(article.author.name)
630
+ }
631
+
632
+ // Цепочка
633
+ meta
634
+ .setAuthor('Иван Иванов')
635
+ .setTitle('Статья')
636
+ .setDescription('Описание')
637
+
638
+ // Для структурированных данных
639
+ meta.setAuthor(author.name)
640
+ ```
641
+
642
+ ### `setSiteName`
643
+
644
+ Устанавливает название сайта для Open Graph и Twitter Card одновременно.
645
+
646
+ **Параметры:**
647
+ - `siteName: string` — название сайта
648
+
649
+ **Возвращает:** `this` — для цепочечных вызовов
650
+
651
+ ```javascript
652
+ const meta = new Meta()
653
+
654
+ // Установка названия сайта
655
+ meta.setSiteName('Мой Блог')
656
+ // Обновляет og:site_name и twitter:site
657
+
658
+ // Из конфигурации
659
+ meta.setSiteName(config.siteName)
660
+
661
+ // Константа
662
+ const SITE_NAME = 'WebDev Journal'
663
+ meta.setSiteName(SITE_NAME)
664
+
665
+ // Для брендинга
666
+ meta.setSiteName('TechBlog')
667
+
668
+ // Один раз при инициализации
669
+ const meta = new Meta()
670
+ meta.setSiteName('Мой Сайт')
671
+ meta.setSuffix('Мой Сайт')
672
+
673
+ // Цепочка
674
+ meta
675
+ .setSiteName('Название Сайта')
676
+ .setTitle('Главная')
677
+
678
+ // Рекомендации:
679
+ // - Краткое и узнаваемое
680
+ // - Соответствует бренду
681
+ // - Используется в социальных сетях
682
+ ```
683
+
684
+ ### `setLocale`
685
+
686
+ Устанавливает локаль для Open Graph.
687
+
688
+ **Параметры:**
689
+ - `locale: string` — локаль в формате language_TERRITORY
690
+
691
+ **Возвращает:** `this` — для цепочечных вызовов
692
+
693
+ ```javascript
694
+ const meta = new Meta()
695
+
696
+ // Установка русской локали
697
+ meta.setLocale('ru_RU')
698
+
699
+ // Другие локали
700
+ meta.setLocale('en_US') // Английский (США)
701
+ meta.setLocale('en_GB') // Английский (Великобритания)
702
+ meta.setLocale('uk_UA') // Украинский
703
+ meta.setLocale('de_DE') // Немецкий
704
+ meta.setLocale('fr_FR') // Французский
705
+
706
+ // Автоматическое определение
707
+ const userLocale = navigator.language.replace('-', '_')
708
+ meta.setLocale(userLocale)
709
+
710
+ // Из настроек i18n
711
+ meta.setLocale(i18n.locale.replace('-', '_'))
712
+
713
+ // Условная установка
714
+ const locale = isRussian ? 'ru_RU' : 'en_US'
715
+ meta.setLocale(locale)
716
+
717
+ // При смене языка
718
+ const changeLanguage = (lang) => {
719
+ const localeMap = {
720
+ 'ru': 'ru_RU',
721
+ 'en': 'en_US',
722
+ 'de': 'de_DE'
723
+ }
724
+ meta.setLocale(localeMap[lang])
725
+ }
726
+
727
+ // Цепочка
728
+ meta
729
+ .setLocale('ru_RU')
730
+ .setSiteName('Мой Сайт')
731
+ ```
732
+
733
+ ### `setSuffix`
734
+
735
+ Устанавливает суффикс для автоматического добавления к заголовку страницы.
736
+
737
+ **Параметры:**
738
+ - `suffix?: string` — суффикс заголовка (необязательный)
739
+
740
+ ```javascript
741
+ const meta = new Meta()
742
+
743
+ // Установка суффикса
744
+ meta.setSuffix('Мой Сайт')
745
+ meta.setTitle('Главная')
746
+ // document.title = "Главная - Мой Сайт"
747
+
748
+ // Из конфигурации
749
+ meta.setSuffix(config.siteName)
750
+
751
+ // Удаление суффикса
752
+ meta.setSuffix()
753
+ meta.setTitle('Страница')
754
+ // document.title = "Страница"
755
+
756
+ // Условная установка
757
+ if (showBranding) {
758
+ meta.setSuffix('Название Сайта')
759
+ }
760
+
761
+ // Разные суффиксы для разных разделов
762
+ if (isBlog) {
763
+ meta.setSuffix('Блог | Мой Сайт')
764
+ } else {
765
+ meta.setSuffix('Мой Сайт')
766
+ }
767
+
768
+ // Обычно устанавливается один раз при инициализации
769
+ const initMeta = () => {
770
+ const meta = new Meta()
771
+ meta.setSuffix('Мой Сайт')
772
+ meta.setSiteName('Мой Сайт')
773
+ return meta
774
+ }
775
+
776
+ // Примечание: суффикс добавляется автоматически
777
+ // в формате: "Заголовок - Суффикс"
778
+ ```
779
+
780
+ ### `html`
781
+
782
+ Генерирует полный HTML для всех мета-тегов, включая Open Graph и Twitter Card.
783
+
784
+ **Возвращает:** `string` — HTML-строка со всеми мета-тегами
785
+
786
+ ```javascript
787
+ const meta = new Meta()
788
+
789
+ // Настройка мета-тегов
790
+ meta.setSuffix('Мой Сайт')
791
+ meta.setSiteName('Мой Сайт')
792
+ meta.setLocale('ru_RU')
793
+ meta
794
+ .setTitle('Статья')
795
+ .setDescription('Описание статьи')
796
+ .setKeywords(['веб', 'javascript'])
797
+ .setImage('https://example.com/image.jpg')
798
+ .setCanonical('https://example.com/article')
799
+ .setAuthor('Иван Иванов')
800
+
801
+ // Получить HTML всех мета-тегов
802
+ const metaHTML = meta.html()
803
+
804
+ // Результат включает:
805
+ // - Стандартные HTML мета-теги (description, keywords, author, canonical)
806
+ // - Open Graph теги (og:title, og:description, og:image, og:url, og:site_name, og:locale)
807
+ // - Twitter Card теги (twitter:title, twitter:description, twitter:image, twitter:site)
808
+
809
+ // Использование в SSR (Server-Side Rendering)
810
+ // Express.js
811
+ app.get('/page', (req, res) => {
812
+ const meta = new Meta()
813
+ meta
814
+ .setTitle('Заголовок страницы')
815
+ .setDescription('Описание')
816
+ .setImage('https://example.com/og-image.jpg')
817
+
818
+ const html = `
819
+ <!DOCTYPE html>
820
+ <html>
821
+ <head>
822
+ <meta charset="UTF-8">
823
+ ${meta.html()}
824
+ <title>Заголовок - Сайт</title>
825
+ </head>
826
+ <body>
827
+ <h1>Контент</h1>
828
+ </body>
829
+ </html>
830
+ `
831
+
832
+ res.send(html)
833
+ })
834
+
835
+ // Next.js getServerSideProps
836
+ export async function getServerSideProps() {
837
+ const meta = new Meta()
838
+ meta
839
+ .setTitle('Статья')
840
+ .setDescription('Описание статьи')
841
+
842
+ return {
843
+ props: {
844
+ metaTags: meta.html()
845
+ }
846
+ }
847
+ }
848
+
849
+ // Nuxt.js (в composable)
850
+ const meta = new Meta()
851
+ meta.setTitle('Страница')
852
+
853
+ const metaHTML = meta.html()
854
+ // Вставить в head через useHead() или в шаблон
855
+
856
+ // Преимущества метода html():
857
+ // - Автоматическое экранирование специальных символов
858
+ // - Объединяет все три типа мета-тегов (standard, OG, Twitter)
859
+ // - Готово для вставки в серверный шаблон
860
+ // - Безопасно от XSS атак
861
+ ```
862
+
863
+ ## Практические примеры
864
+
865
+ ### Полная настройка страницы
866
+
867
+ ```javascript
868
+ import { Meta, MetaRobots } from '@dxtmisha/functional'
869
+
870
+ const meta = new Meta()
871
+
872
+ // Настройка при инициализации приложения
873
+ meta.setSuffix('Мой Сайт')
874
+ meta.setSiteName('Мой Сайт')
875
+ meta.setLocale('ru_RU')
876
+
877
+ // Настройка конкретной страницы
878
+ meta
879
+ .setTitle('Полное руководство по веб-разработке')
880
+ .setDescription('Изучите веб-разработку с нуля: HTML, CSS, JavaScript, фреймворки и инструменты')
881
+ .setKeywords(['веб-разработка', 'html', 'css', 'javascript', 'руководство'])
882
+ .setImage('https://example.com/images/web-dev-guide.jpg')
883
+ .setCanonical('https://example.com/guides/web-development')
884
+ .setAuthor('Иван Иванов')
885
+ .setRobots(MetaRobots.indexFollow)
886
+
887
+ // Результат:
888
+ // <title>Полное руководство по веб-разработке - Мой Сайт</title>
889
+ // <meta name="description" content="Изучите веб-разработку...">
890
+ // <meta name="keywords" content="веб-разработка, html, css, javascript, руководство">
891
+ // <meta name="author" content="Иван Иванов">
892
+ // <meta name="robots" content="index, follow">
893
+ // <link rel="canonical" href="https://example.com/guides/web-development">
894
+ // <meta property="og:title" content="Полное руководство... - Мой Сайт">
895
+ // <meta property="og:description" content="Изучите веб-разработку...">
896
+ // <meta property="og:image" content="https://example.com/images/web-dev-guide.jpg">
897
+ // <meta property="og:url" content="https://example.com/guides/web-development">
898
+ // <meta property="og:site_name" content="Мой Сайт">
899
+ // <meta property="og:locale" content="ru_RU">
900
+ // <meta property="twitter:title" content="Полное руководство... - Мой Сайт">
901
+ // <meta property="twitter:description" content="Изучите веб-разработку...">
902
+ // <meta property="twitter:image" content="https://example.com/images/web-dev-guide.jpg">
903
+ // <meta property="twitter:site" content="Мой Сайт">
904
+ ```
905
+
906
+ ### Интеграция с Vue Router
907
+
908
+ ```javascript
909
+ import { Meta } from '@dxtmisha/functional'
910
+
911
+ const meta = new Meta()
912
+
913
+ // Инициализация
914
+ meta.setSuffix('Мой Сайт')
915
+ meta.setSiteName('Мой Сайт')
916
+ meta.setLocale('ru_RU')
917
+
918
+ // Обновление при смене роута
919
+ router.afterEach((to) => {
920
+ meta
921
+ .setTitle(to.meta.title || 'Страница не найдена')
922
+ .setDescription(to.meta.description || '')
923
+ .setKeywords(to.meta.keywords || [])
924
+ .setCanonical(`https://example.com${to.path}`)
925
+
926
+ // Изображение если есть
927
+ if (to.meta.image) {
928
+ meta.setImage(to.meta.image)
929
+ }
930
+
931
+ // Автор если есть
932
+ if (to.meta.author) {
933
+ meta.setAuthor(to.meta.author)
934
+ }
935
+ })
936
+
937
+ // Определение мета в роутах
938
+ const routes = [
939
+ {
940
+ path: '/',
941
+ component: Home,
942
+ meta: {
943
+ title: 'Главная',
944
+ description: 'Добро пожаловать на наш сайт',
945
+ keywords: ['главная', 'сайт'],
946
+ image: '/images/home.jpg'
947
+ }
948
+ },
949
+ {
950
+ path: '/about',
951
+ component: About,
952
+ meta: {
953
+ title: 'О нас',
954
+ description: 'Информация о нашей компании',
955
+ keywords: ['о нас', 'компания'],
956
+ image: '/images/about.jpg'
957
+ }
958
+ }
959
+ ]
960
+ ```
961
+
962
+ ### Интеграция с React
963
+
964
+ ```javascript
965
+ import { Meta } from '@dxtmisha/functional'
966
+ import { useEffect } from 'react'
967
+
968
+ const meta = new Meta()
969
+
970
+ // Инициализация в App.js
971
+ function App() {
972
+ useEffect(() => {
973
+ meta.setSuffix('Мой Сайт')
974
+ meta.setSiteName('Мой Сайт')
975
+ meta.setLocale('en_US')
976
+ }, [])
977
+
978
+ return <Router />
979
+ }
980
+
981
+ // Компонент страницы
982
+ function ArticlePage({ article }) {
983
+ useEffect(() => {
984
+ meta
985
+ .setTitle(article.title)
986
+ .setDescription(article.excerpt)
987
+ .setKeywords(article.tags)
988
+ .setImage(article.coverImage)
989
+ .setCanonical(`https://example.com/articles/${article.slug}`)
990
+ .setAuthor(article.author.name)
991
+
992
+ return () => {
993
+ // Очистка при размонтировании (опционально)
994
+ }
995
+ }, [article])
996
+
997
+ return <div>{/* контент */}</div>
998
+ }
999
+
1000
+ // Custom hook для мета-тегов
1001
+ function useMeta(metaData) {
1002
+ useEffect(() => {
1003
+ if (metaData.title) meta.setTitle(metaData.title)
1004
+ if (metaData.description) meta.setDescription(metaData.description)
1005
+ if (metaData.keywords) meta.setKeywords(metaData.keywords)
1006
+ if (metaData.image) meta.setImage(metaData.image)
1007
+ if (metaData.canonical) meta.setCanonical(metaData.canonical)
1008
+ if (metaData.author) meta.setAuthor(metaData.author)
1009
+ }, [metaData])
1010
+ }
1011
+
1012
+ // Использование hook
1013
+ function BlogPost({ post }) {
1014
+ useMeta({
1015
+ title: post.title,
1016
+ description: post.excerpt,
1017
+ keywords: post.tags,
1018
+ image: post.image,
1019
+ author: post.author.name
1020
+ })
1021
+
1022
+ return <article>{/* контент */}</article>
1023
+ }
1024
+ ```
1025
+
1026
+ ### Динамическое обновление из API
1027
+
1028
+ ```javascript
1029
+ import { Meta } from '@dxtmisha/functional'
1030
+
1031
+ const meta = new Meta()
1032
+
1033
+ // Загрузка страницы из API
1034
+ async function loadPage(pageId) {
1035
+ const response = await fetch(`/api/pages/${pageId}`)
1036
+ const page = await response.json()
1037
+
1038
+ // Обновление всех мета-тегов
1039
+ meta
1040
+ .setTitle(page.title)
1041
+ .setDescription(page.description)
1042
+ .setKeywords(page.keywords)
1043
+ .setImage(page.image)
1044
+ .setCanonical(page.url)
1045
+ .setAuthor(page.author)
1046
+
1047
+ return page
1048
+ }
1049
+
1050
+ // Обработка разных типов контента
1051
+ async function updateMetaForContent(contentType, contentId) {
1052
+ const content = await fetchContent(contentType, contentId)
1053
+
1054
+ switch (contentType) {
1055
+ case 'article':
1056
+ meta
1057
+ .setTitle(content.title)
1058
+ .setDescription(content.excerpt)
1059
+ .setKeywords(content.tags)
1060
+ .setImage(content.coverImage)
1061
+ .setAuthor(content.author.name)
1062
+ break
1063
+
1064
+ case 'product':
1065
+ meta
1066
+ .setTitle(content.name)
1067
+ .setDescription(content.description)
1068
+ .setKeywords([content.category, ...content.tags])
1069
+ .setImage(content.images[0])
1070
+ break
1071
+
1072
+ case 'video':
1073
+ meta
1074
+ .setTitle(content.title)
1075
+ .setDescription(content.synopsis)
1076
+ .setImage(content.thumbnail)
1077
+ break
1078
+ }
1079
+ }
1080
+ ```
1081
+
1082
+ ### SSR (Server-Side Rendering)
1083
+
1084
+ ```javascript
1085
+ import { Meta } from '@dxtmisha/functional'
1086
+
1087
+ // Express.js сервер
1088
+ app.get('/article/:id', async (req, res) => {
1089
+ const article = await getArticle(req.params.id)
1090
+
1091
+ const meta = new Meta()
1092
+ meta.setSuffix('Мой Блог')
1093
+ meta.setSiteName('Мой Блог')
1094
+ meta.setLocale('ru_RU')
1095
+
1096
+ meta
1097
+ .setTitle(article.title)
1098
+ .setDescription(article.excerpt)
1099
+ .setKeywords(article.tags)
1100
+ .setImage(article.coverImage)
1101
+ .setCanonical(`https://example.com/article/${article.id}`)
1102
+ .setAuthor(article.author.name)
1103
+
1104
+ const html = `
1105
+ <!DOCTYPE html>
1106
+ <html lang="ru">
1107
+ <head>
1108
+ <meta charset="UTF-8">
1109
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
1110
+ <title>${article.title} - Мой Блог</title>
1111
+ ${meta.html()}
1112
+ </head>
1113
+ <body>
1114
+ <article>${article.content}</article>
1115
+ </body>
1116
+ </html>
1117
+ `
1118
+
1119
+ res.send(html)
1120
+ })
1121
+
1122
+ // Next.js
1123
+ export async function getServerSideProps({ params }) {
1124
+ const article = await getArticle(params.id)
1125
+
1126
+ const meta = new Meta()
1127
+ meta.setSuffix('Мой Блог')
1128
+ meta
1129
+ .setTitle(article.title)
1130
+ .setDescription(article.excerpt)
1131
+ .setKeywords(article.tags)
1132
+ .setImage(article.coverImage)
1133
+
1134
+ return {
1135
+ props: {
1136
+ article,
1137
+ metaHtml: meta.html()
1138
+ }
1139
+ }
1140
+ }
1141
+ ```
1142
+
1143
+ ### Управление robots для разных сценариев
1144
+
1145
+ ```javascript
1146
+ import { Meta, MetaRobots } from '@dxtmisha/functional'
1147
+
1148
+ const meta = new Meta()
1149
+
1150
+ // Функция определения robots директивы
1151
+ function setRobotsForPage(pageType, pageStatus) {
1152
+ switch (pageType) {
1153
+ case 'article':
1154
+ if (pageStatus === 'published') {
1155
+ meta.setRobots(MetaRobots.indexFollow)
1156
+ } else if (pageStatus === 'draft') {
1157
+ meta.setRobots(MetaRobots.noindexNofollow)
1158
+ }
1159
+ break
1160
+
1161
+ case 'search':
1162
+ // Страницы поиска не индексируем
1163
+ meta.setRobots(MetaRobots.noindexFollow)
1164
+ break
1165
+
1166
+ case 'login':
1167
+ case 'admin':
1168
+ // Закрытые страницы
1169
+ meta.setRobots(MetaRobots.noindexNofollow)
1170
+ break
1171
+
1172
+ case 'pagination':
1173
+ // Страницы пагинации
1174
+ meta.setRobots(MetaRobots.noindexFollow)
1175
+ break
1176
+
1177
+ default:
1178
+ meta.setRobots(MetaRobots.indexFollow)
1179
+ }
1180
+ }
1181
+
1182
+ // Условная логика
1183
+ if (isUserAuthenticated && isPrivatePage) {
1184
+ meta.setRobots(MetaRobots.noindexNofollow)
1185
+ } else {
1186
+ meta.setRobots(MetaRobots.indexFollow)
1187
+ }
1188
+ ```
1189
+
1190
+ ### Использование расширенных возможностей Open Graph и Twitter Card
1191
+
1192
+ ```javascript
1193
+ import { Meta, MetaOpenGraphType, MetaTwitterCard } from '@dxtmisha/functional'
1194
+
1195
+ const meta = new Meta()
1196
+
1197
+ // Базовая настройка через Meta
1198
+ meta
1199
+ .setTitle('Видео: Введение в JavaScript')
1200
+ .setDescription('Полное видео руководство по JavaScript для начинающих')
1201
+ .setImage('https://example.com/images/js-video-thumb.jpg')
1202
+ .setCanonical('https://example.com/videos/js-intro')
1203
+
1204
+ // Расширенная настройка Open Graph через getOg()
1205
+ meta.getOg()
1206
+ .setType(MetaOpenGraphType.videoMovie) // Тип: видео
1207
+ .setLocale('ru_RU')
1208
+
1209
+ // Расширенная настройка Twitter Card через getTwitter()
1210
+ meta.getTwitter()
1211
+ .setCard(MetaTwitterCard.player) // Карточка с плеером
1212
+ .setCreator('@javascript_guru') // Автор видео
1213
+
1214
+ // Комбинированная настройка для разных типов контента
1215
+ const setupContentMeta = (content) => {
1216
+ // Общие настройки
1217
+ meta
1218
+ .setTitle(content.title)
1219
+ .setDescription(content.description)
1220
+ .setImage(content.image)
1221
+ .setCanonical(content.url)
1222
+
1223
+ // Специфичные настройки в зависимости от типа
1224
+ switch (content.type) {
1225
+ case 'article':
1226
+ meta.getOg().setType(MetaOpenGraphType.article)
1227
+ meta.getTwitter().setCard(MetaTwitterCard.summaryLargeImage)
1228
+ if (content.author?.twitter) {
1229
+ meta.getTwitter().setCreator(content.author.twitter)
1230
+ }
1231
+ break
1232
+
1233
+ case 'video':
1234
+ meta.getOg().setType(MetaOpenGraphType.videoMovie)
1235
+ meta.getTwitter().setCard(MetaTwitterCard.player)
1236
+ break
1237
+
1238
+ case 'product':
1239
+ meta.getOg().setType(MetaOpenGraphType.product)
1240
+ meta.getTwitter().setCard(MetaTwitterCard.summaryLargeImage)
1241
+ break
1242
+
1243
+ case 'music':
1244
+ meta.getOg().setType(MetaOpenGraphType.musicSong)
1245
+ meta.getTwitter().setCard(MetaTwitterCard.player)
1246
+ break
1247
+ }
1248
+ }
1249
+
1250
+ // Использование
1251
+ setupContentMeta({
1252
+ type: 'video',
1253
+ title: 'JavaScript Tutorial',
1254
+ description: 'Learn JavaScript from scratch',
1255
+ image: 'https://example.com/thumb.jpg',
1256
+ url: 'https://example.com/videos/js-tutorial',
1257
+ author: {
1258
+ twitter: '@instructor'
1259
+ }
1260
+ })
1261
+
1262
+ // Доступ к специфичным методам
1263
+ const getFullMetaInfo = () => {
1264
+ return {
1265
+ // Через Meta
1266
+ title: meta.getTitle(),
1267
+ description: meta.getDescription(),
1268
+ image: meta.getImage(),
1269
+
1270
+ // Через MetaOg
1271
+ ogType: meta.getOg().getType(),
1272
+ ogLocale: meta.getOg().getLocale(),
1273
+
1274
+ // Через MetaTwitter
1275
+ twitterCard: meta.getTwitter().getCard(),
1276
+ twitterCreator: meta.getTwitter().getCreator()
1277
+ }
1278
+ }
1279
+ ```
1280
+
1281
+ ## Рекомендации по использованию
1282
+
1283
+ ### Инициализация
1284
+ Установите общие параметры один раз при запуске приложения:
1285
+ ```javascript
1286
+ const meta = new Meta()
1287
+ meta.setSuffix('Название Сайта')
1288
+ meta.setSiteName('Название Сайта')
1289
+ meta.setLocale('ru_RU')
1290
+ ```
1291
+
1292
+ ### Обновление при навигации
1293
+ Обновляйте мета-теги при смене страницы:
1294
+ ```javascript
1295
+ router.afterEach((to) => {
1296
+ meta
1297
+ .setTitle(to.meta.title)
1298
+ .setDescription(to.meta.description)
1299
+ .setCanonical(`https://example.com${to.path}`)
1300
+ })
1301
+ ```
1302
+
1303
+ ### Длина текста
1304
+ - **Title:** до 60 символов (без суффикса)
1305
+ - **Description:** 150-160 символов
1306
+ - **Keywords:** 10-15 ключевых слов
1307
+
1308
+ ### Обязательные теги
1309
+ Минимально необходимые мета-теги:
1310
+ - Title (через `setTitle`)
1311
+ - Description (через `setDescription`)
1312
+ - Canonical (через `setCanonical`)
1313
+ - Image для социальных сетей (через `setImage`)
1314
+
1315
+ ### Изображения
1316
+ - Размер: 1200×630 px (оптимально)
1317
+ - Формат: JPG, PNG, WebP
1318
+ - Максимум: 8 MB
1319
+
1320
+ ## Примечания
1321
+
1322
+ - Класс объединяет функциональность MetaManager, MetaOg и MetaTwitter
1323
+ - Изменения в Meta автоматически применяются ко всем связанным мета-тегам
1324
+ - Суффикс добавляется только к document.title и социальным тегам
1325
+ - Метод `html()` наследуется от MetaManager и генерирует HTML для всех управляемых тегов
1326
+ - Класс совместим с SSR — проверяет наличие DOM перед доступом к document
1327
+ - Keywords менее важны для современного SEO, но могут использоваться для внутреннего поиска
1328
+ - Для расширенной работы с Open Graph используйте напрямую `meta.og`
1329
+ - Для расширенной работы с Twitter Card используйте напрямую `meta.twitter`
1330
+