@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,853 @@
1
+ import {Meta} from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title='@dxtmisha/functional/ru/Classes/MetaTwitter'/>
4
+
5
+ # Класс MetaTwitter
6
+
7
+ Класс для работы с Twitter Card мета-тегами, обеспечивающий красивое отображение контента при публикации ссылок в Twitter (X). Наследует функциональность `MetaManager` и предоставляет типобезопасные методы для управления стандартными Twitter Card тегами.
8
+
9
+ ## Основные возможности
10
+
11
+ - **Типобезопасность** — строгая типизация для всех Twitter Card тегов и типов карточек
12
+ - **Автоматическая синхронизация** — обновление мета-тегов в `<head>` документа
13
+ - **Поддержка всех типов карточек** — summary, summary_large_image, app, player
14
+ - **Удобный API** — специализированные методы для каждого тега
15
+ - **SSR совместимость** — генерация HTML для серверного рендеринга
16
+ - **Валидация типов** — поддержка всех официальных типов Twitter Cards
17
+ - **Цепочечные методы** — возможность последовательной установки значений
18
+
19
+ ## Конструктор
20
+
21
+ ### `constructor`
22
+
23
+ Создает экземпляр MetaTwitter с предустановленным списком всех поддерживаемых Twitter Card тегов. Автоматически считывает существующие теги из DOM.
24
+
25
+ ```javascript
26
+ import { MetaTwitter } from '@dxtmisha/functional'
27
+
28
+ // Создание экземпляра
29
+ const twitter = new MetaTwitter()
30
+
31
+ // Класс автоматически управляет всеми стандартными Twitter Card тегами:
32
+ // twitter:card, twitter:site, twitter:creator, twitter:title,
33
+ // twitter:description, twitter:image и другими
34
+ ```
35
+
36
+ ## Методы получения данных
37
+
38
+ ### `getCard`
39
+
40
+ Получает тип Twitter Card.
41
+
42
+ **Возвращает:** `MetaTwitterCard` — тип карточки
43
+
44
+ ```javascript
45
+ const twitter = new MetaTwitter()
46
+
47
+ const cardType = twitter.getCard()
48
+ // 'summary_large_image'
49
+
50
+ // Проверка типа карточки
51
+ if (twitter.getCard() === 'summary_large_image') {
52
+ console.log('Карточка с большим изображением')
53
+ }
54
+
55
+ // Условная логика
56
+ switch (twitter.getCard()) {
57
+ case 'summary':
58
+ console.log('Обычная карточка')
59
+ break
60
+ case 'summary_large_image':
61
+ console.log('Карточка с большим изображением')
62
+ break
63
+ case 'player':
64
+ console.log('Видео плеер')
65
+ break
66
+ }
67
+ ```
68
+
69
+ ### `getSite`
70
+
71
+ Получает Twitter аккаунт сайта или бренда.
72
+
73
+ **Возвращает:** `string` — @username сайта
74
+
75
+ ```javascript
76
+ const twitter = new MetaTwitter()
77
+
78
+ const site = twitter.getSite()
79
+ // '@mywebsite'
80
+
81
+ // Использование для атрибуции
82
+ console.log('Сайт принадлежит:', twitter.getSite())
83
+
84
+ // Проверка наличия
85
+ if (twitter.getSite()) {
86
+ console.log('Twitter аккаунт сайта установлен')
87
+ }
88
+
89
+ // Извлечение имени без @
90
+ const username = twitter.getSite().replace('@', '')
91
+ ```
92
+
93
+ ### `getCreator`
94
+
95
+ Получает Twitter аккаунт автора контента.
96
+
97
+ **Возвращает:** `string` — @username автора
98
+
99
+ ```javascript
100
+ const twitter = new MetaTwitter()
101
+
102
+ const creator = twitter.getCreator()
103
+ // '@john_doe'
104
+
105
+ // Отображение автора
106
+ console.log('Автор:', twitter.getCreator())
107
+
108
+ // Использование в UI
109
+ const authorLink = `https://twitter.com/${twitter.getCreator().replace('@', '')}`
110
+
111
+ // Проверка авторства
112
+ if (twitter.getCreator()) {
113
+ console.log('У контента есть автор')
114
+ }
115
+ ```
116
+
117
+ ### `getUrl`
118
+
119
+ Получает URL страницы для Twitter Card.
120
+
121
+ **Возвращает:** `string` — URL страницы
122
+
123
+ ```javascript
124
+ const twitter = new MetaTwitter()
125
+
126
+ const url = twitter.getUrl()
127
+ // 'https://example.com/article/my-post'
128
+
129
+ // Получение домена
130
+ const domain = new URL(twitter.getUrl()).hostname
131
+
132
+ // Проверка совпадения с текущим URL
133
+ if (twitter.getUrl() !== window.location.href) {
134
+ console.warn('Twitter URL не совпадает с текущим')
135
+ }
136
+
137
+ // Создание ссылки для шаринга
138
+ const shareUrl = `https://twitter.com/intent/tweet?url=${encodeURIComponent(twitter.getUrl())}`
139
+ ```
140
+
141
+ ### `getTitle`
142
+
143
+ Получает заголовок карточки.
144
+
145
+ **Возвращает:** `string` — заголовок карточки
146
+
147
+ ```javascript
148
+ const twitter = new MetaTwitter()
149
+
150
+ const title = twitter.getTitle()
151
+ // 'Удивительная статья о веб-разработке'
152
+
153
+ // Использование для отладки
154
+ console.log('Twitter Title:', twitter.getTitle())
155
+
156
+ // Проверка длины (рекомендуется до 70 символов)
157
+ if (twitter.getTitle().length > 70) {
158
+ console.warn('Заголовок слишком длинный для Twitter')
159
+ }
160
+
161
+ // Использование в превью
162
+ const previewTitle = twitter.getTitle()
163
+ ```
164
+
165
+ ### `getDescription`
166
+
167
+ Получает описание карточки.
168
+
169
+ **Возвращает:** `string` — описание карточки
170
+
171
+ ```javascript
172
+ const twitter = new MetaTwitter()
173
+
174
+ const description = twitter.getDescription()
175
+ // 'Подробное руководство по созданию...'
176
+
177
+ // Проверка длины (рекомендуется до 200 символов)
178
+ if (twitter.getDescription().length > 200) {
179
+ console.warn('Описание слишком длинное')
180
+ }
181
+
182
+ // Обрезка для превью
183
+ const shortDesc = twitter.getDescription().substring(0, 150) + '...'
184
+
185
+ // Использование в мета-данных
186
+ console.log('Twitter Description:', twitter.getDescription())
187
+ ```
188
+
189
+ ### `getImage`
190
+
191
+ Получает URL изображения карточки.
192
+
193
+ **Возвращает:** `string` — URL изображения
194
+
195
+ ```javascript
196
+ const twitter = new MetaTwitter()
197
+
198
+ const imageUrl = twitter.getImage()
199
+ // 'https://example.com/images/twitter-card.jpg'
200
+
201
+ // Предзагрузка изображения
202
+ const img = new Image()
203
+ img.src = twitter.getImage()
204
+
205
+ // Проверка наличия
206
+ if (!twitter.getImage()) {
207
+ console.warn('Twitter изображение не установлено')
208
+ }
209
+
210
+ // Использование для превью
211
+ const previewImage = twitter.getImage()
212
+ ```
213
+
214
+ ## Методы установки данных
215
+
216
+ ### `setCard`
217
+
218
+ Устанавливает тип Twitter Card.
219
+
220
+ **Параметры:**
221
+ - `card: MetaTwitterCard` — тип карточки
222
+
223
+ **Возвращает:** `this` — для цепочечных вызовов
224
+
225
+ **Доступные типы:**
226
+ - `summary` — карточка-сводка с небольшим изображением
227
+ - `summary_large_image` — карточка с большим изображением (самый популярный)
228
+ - `app` — карточка приложения (для iOS/Android)
229
+ - `player` — карточка с видео/аудио плеером
230
+
231
+ ```javascript
232
+ import { MetaTwitter, MetaTwitterCard } from '@dxtmisha/functional'
233
+
234
+ const twitter = new MetaTwitter()
235
+
236
+ // Установка стандартной карточки
237
+ twitter.setCard(MetaTwitterCard.summary)
238
+
239
+ // Карточка с большим изображением (рекомендуется)
240
+ twitter.setCard(MetaTwitterCard.summaryLargeImage)
241
+
242
+ // Для приложений
243
+ twitter.setCard(MetaTwitterCard.app)
244
+
245
+ // Для видео контента
246
+ twitter.setCard(MetaTwitterCard.player)
247
+
248
+ // Условная установка
249
+ const cardType = hasLargeImage
250
+ ? MetaTwitterCard.summaryLargeImage
251
+ : MetaTwitterCard.summary
252
+
253
+ twitter.setCard(cardType)
254
+ ```
255
+
256
+ ### `setSite`
257
+
258
+ Устанавливает Twitter аккаунт сайта или бренда.
259
+
260
+ **Параметры:**
261
+ - `site: string` — @username сайта
262
+
263
+ **Возвращает:** `this` — для цепочечных вызовов
264
+
265
+ ```javascript
266
+ const twitter = new MetaTwitter()
267
+
268
+ // Установка аккаунта сайта
269
+ twitter.setSite('@mywebsite')
270
+
271
+ // Можно без @
272
+ twitter.setSite('mywebsite')
273
+
274
+ // Из конфигурации
275
+ twitter.setSite(config.twitterHandle)
276
+
277
+ // Цепочка методов
278
+ twitter
279
+ .setSite('@mywebsite')
280
+ .setCreator('@author')
281
+
282
+ // Рекомендации:
283
+ // - Используйте официальный аккаунт бренда
284
+ // - Формат: @username (с @ или без)
285
+ // - Twitter будет показывать "via @username" в карточке
286
+ ```
287
+
288
+ ### `setCreator`
289
+
290
+ Устанавливает Twitter аккаунт автора контента.
291
+
292
+ **Параметры:**
293
+ - `creator: string` — @username автора
294
+
295
+ **Возвращает:** `this` — для цепочечных вызовов
296
+
297
+ ```javascript
298
+ const twitter = new MetaTwitter()
299
+
300
+ // Установка автора
301
+ twitter.setCreator('@john_doe')
302
+
303
+ // Из данных пользователя
304
+ twitter.setCreator(article.author.twitterHandle)
305
+
306
+ // Динамическое обновление
307
+ const updateAuthor = (author) => {
308
+ if (author.twitter) {
309
+ twitter.setCreator(author.twitter)
310
+ }
311
+ }
312
+
313
+ // Цепочка
314
+ twitter
315
+ .setCreator('@author_name')
316
+ .setTitle('Заголовок статьи')
317
+
318
+ // Рекомендации:
319
+ // - Используйте для атрибуции автора
320
+ // - Twitter покажет "by @username"
321
+ // - Отличается от site (site - для сайта, creator - для автора)
322
+ ```
323
+
324
+ ### `setUrl`
325
+
326
+ Устанавливает URL страницы для Twitter Card.
327
+
328
+ **Параметры:**
329
+ - `url: string` — URL страницы
330
+
331
+ **Возвращает:** `this` — для цепочечных вызовов
332
+
333
+ ```javascript
334
+ const twitter = new MetaTwitter()
335
+
336
+ // Установка URL
337
+ twitter.setUrl('https://example.com/article/my-post')
338
+
339
+ // Использование текущего URL
340
+ twitter.setUrl(window.location.href)
341
+
342
+ // Очистка query параметров
343
+ const cleanUrl = window.location.origin + window.location.pathname
344
+ twitter.setUrl(cleanUrl)
345
+
346
+ // Для SPA
347
+ router.afterEach((to) => {
348
+ twitter.setUrl(`https://example.com${to.fullPath}`)
349
+ })
350
+
351
+ // Абсолютный URL из относительного
352
+ const absoluteUrl = new URL('/article', window.location.origin).href
353
+ twitter.setUrl(absoluteUrl)
354
+
355
+ // Рекомендации:
356
+ // - Всегда используйте абсолютные URL
357
+ // - URL должен быть доступен для Twitter бота
358
+ // - Избегайте редиректов
359
+ ```
360
+
361
+ ### `setTitle`
362
+
363
+ Устанавливает заголовок карточки.
364
+
365
+ **Параметры:**
366
+ - `title: string` — заголовок карточки
367
+
368
+ **Возвращает:** `this` — для цепочечных вызовов
369
+
370
+ ```javascript
371
+ const twitter = new MetaTwitter()
372
+
373
+ // Установка заголовка
374
+ twitter.setTitle('Потрясающая статья о веб-разработке')
375
+
376
+ // Цепочка методов
377
+ twitter
378
+ .setTitle('Новый заголовок')
379
+ .setDescription('Новое описание')
380
+
381
+ // Динамическое обновление
382
+ const updateTitle = (newTitle) => {
383
+ twitter.setTitle(newTitle)
384
+ }
385
+
386
+ // Автоматическая генерация
387
+ twitter.setTitle(`${article.title} - ${siteName}`)
388
+
389
+ // Обрезка длинного заголовка
390
+ const maxLength = 70
391
+ const shortTitle = article.title.length > maxLength
392
+ ? article.title.substring(0, maxLength - 3) + '...'
393
+ : article.title
394
+
395
+ twitter.setTitle(shortTitle)
396
+
397
+ // Рекомендации:
398
+ // - Максимум 70 символов
399
+ // - Будет отображаться жирным шрифтом
400
+ // - Избегайте дублирования с описанием
401
+ ```
402
+
403
+ ### `setDescription`
404
+
405
+ Устанавливает описание карточки.
406
+
407
+ **Параметры:**
408
+ - `description: string` — описание карточки
409
+
410
+ **Возвращает:** `this` — для цепочечных вызовов
411
+
412
+ ```javascript
413
+ const twitter = new MetaTwitter()
414
+
415
+ // Установка описания
416
+ twitter.setDescription('Полное руководство по созданию веб-приложений с использованием современных технологий')
417
+
418
+ // Обрезка длинного текста
419
+ const shortDesc = article.content.substring(0, 200)
420
+ twitter.setDescription(shortDesc)
421
+
422
+ // Удаление HTML тегов
423
+ const plainText = article.html.replace(/<[^>]*>/g, '')
424
+ twitter.setDescription(plainText.substring(0, 200))
425
+
426
+ // Из excerpt
427
+ twitter.setDescription(article.excerpt || article.content.substring(0, 200))
428
+
429
+ // Цепочка
430
+ twitter
431
+ .setDescription('Описание статьи')
432
+ .setImage('https://example.com/image.jpg')
433
+
434
+ // Рекомендации:
435
+ // - Максимум 200 символов
436
+ // - Twitter может обрезать текст
437
+ // - Добавляйте call-to-action
438
+ // - Избегайте специальных символов
439
+ ```
440
+
441
+ ### `setImage`
442
+
443
+ Устанавливает URL изображения карточки.
444
+
445
+ **Параметры:**
446
+ - `image: string` — URL изображения
447
+
448
+ **Возвращает:** `this` — для цепочечных вызовов
449
+
450
+ ```javascript
451
+ const twitter = new MetaTwitter()
452
+
453
+ // Установка изображения
454
+ twitter.setImage('https://example.com/images/twitter-card.jpg')
455
+
456
+ // Абсолютный URL
457
+ const imageUrl = new URL('/images/twitter-image.jpg', window.location.origin).href
458
+ twitter.setImage(imageUrl)
459
+
460
+ // Из данных контента
461
+ twitter.setImage(article.featuredImage)
462
+
463
+ // Fallback изображение
464
+ twitter.setImage(article.image || '/images/default-twitter.jpg')
465
+
466
+ // Для summary карточки (квадратное изображение)
467
+ twitter
468
+ .setCard(MetaTwitterCard.summary)
469
+ .setImage('https://example.com/square-image.jpg') // 1:1 ratio
470
+
471
+ // Для summary_large_image (широкое изображение)
472
+ twitter
473
+ .setCard(MetaTwitterCard.summaryLargeImage)
474
+ .setImage('https://example.com/wide-image.jpg') // 2:1 ratio
475
+
476
+ // Рекомендуемые размеры:
477
+ // summary: 120x120 - 1:1 (минимум)
478
+ // 280x150 - оптимально
479
+ // summary_large_image: 300x157 - минимум
480
+ // 1200x628 - оптимально (как OG)
481
+ // Ratio 2:1 или 1.91:1
482
+ // Форматы: JPG, PNG, WebP, GIF
483
+ // Максимальный размер: 5 MB
484
+ ```
485
+
486
+ ## Практические примеры
487
+
488
+ ### Полная настройка страницы статьи
489
+
490
+ ```javascript
491
+ import { MetaTwitter, MetaTwitterCard } from '@dxtmisha/functional'
492
+
493
+ const twitter = new MetaTwitter()
494
+
495
+ // Установка всех основных тегов
496
+ twitter
497
+ .setCard(MetaTwitterCard.summaryLargeImage)
498
+ .setTitle('Полное руководство по Twitter Cards')
499
+ .setDescription('Узнайте, как правильно настроить Twitter Card теги для вашего сайта и улучшить отображение в Twitter')
500
+ .setUrl('https://example.com/articles/twitter-cards-guide')
501
+ .setImage('https://example.com/images/twitter-guide.jpg')
502
+ .setSite('@mywebsite')
503
+ .setCreator('@author_name')
504
+
505
+ // Теперь при публикации в Twitter:
506
+ // - Отобразится красивая карточка с большим изображением
507
+ // - Будет показан заголовок и описание
508
+ // - Появится атрибуция "via @mywebsite by @author_name"
509
+ ```
510
+
511
+ ### Динамическое обновление для SPA
512
+
513
+ ```javascript
514
+ // Vue Router
515
+ router.afterEach((to) => {
516
+ const twitter = new MetaTwitter()
517
+
518
+ twitter
519
+ .setCard(MetaTwitterCard.summaryLargeImage)
520
+ .setTitle(to.meta.twitterTitle || to.meta.title)
521
+ .setDescription(to.meta.twitterDescription || to.meta.description)
522
+ .setUrl(`https://example.com${to.path}`)
523
+ .setImage(to.meta.twitterImage || '/images/default-twitter.jpg')
524
+ .setSite('@mywebsite')
525
+ })
526
+
527
+ // React Router
528
+ useEffect(() => {
529
+ const twitter = new MetaTwitter()
530
+
531
+ twitter
532
+ .setCard(MetaTwitterCard.summaryLargeImage)
533
+ .setTitle(page.title)
534
+ .setDescription(page.description)
535
+ .setUrl(window.location.href)
536
+ .setImage(page.image)
537
+ .setSite(config.twitterSite)
538
+ .setCreator(page.author?.twitter)
539
+
540
+ return () => {
541
+ // Cleanup если необходимо
542
+ }
543
+ }, [page])
544
+ ```
545
+
546
+ ### Настройка для разных типов контента
547
+
548
+ ```javascript
549
+ import { MetaTwitter, MetaTwitterCard } from '@dxtmisha/functional'
550
+
551
+ const twitter = new MetaTwitter()
552
+
553
+ // Для блог-поста
554
+ const setupBlogPost = (post) => {
555
+ twitter
556
+ .setCard(MetaTwitterCard.summaryLargeImage)
557
+ .setTitle(post.title)
558
+ .setDescription(post.excerpt)
559
+ .setUrl(`https://example.com/blog/${post.slug}`)
560
+ .setImage(post.coverImage)
561
+ .setSite('@myblog')
562
+ .setCreator(post.author.twitter)
563
+ }
564
+
565
+ // Для новости (с небольшим изображением)
566
+ const setupNews = (news) => {
567
+ twitter
568
+ .setCard(MetaTwitterCard.summary)
569
+ .setTitle(news.headline)
570
+ .setDescription(news.summary)
571
+ .setUrl(`https://example.com/news/${news.id}`)
572
+ .setImage(news.thumbnail)
573
+ .setSite('@mynews')
574
+ }
575
+
576
+ // Для видео
577
+ const setupVideo = (video) => {
578
+ twitter
579
+ .setCard(MetaTwitterCard.player)
580
+ .setTitle(video.title)
581
+ .setDescription(video.description)
582
+ .setUrl(`https://example.com/videos/${video.id}`)
583
+ .setImage(video.thumbnail)
584
+ .setSite('@myvideos')
585
+ }
586
+
587
+ // Для главной страницы
588
+ const setupHomePage = () => {
589
+ twitter
590
+ .setCard(MetaTwitterCard.summaryLargeImage)
591
+ .setTitle('Добро пожаловать на наш сайт')
592
+ .setDescription('Лучший контент о веб-разработке и технологиях')
593
+ .setUrl('https://example.com')
594
+ .setImage('https://example.com/images/home-twitter.jpg')
595
+ .setSite('@mywebsite')
596
+ }
597
+ ```
598
+
599
+ ### Генерация HTML для SSR
600
+
601
+ ```javascript
602
+ import { MetaTwitter, MetaTwitterCard } from '@dxtmisha/functional'
603
+
604
+ // Express.js сервер
605
+ app.get('/article/:id', async (req, res) => {
606
+ const article = await getArticle(req.params.id)
607
+
608
+ const twitter = new MetaTwitter()
609
+ twitter
610
+ .setCard(MetaTwitterCard.summaryLargeImage)
611
+ .setTitle(article.title)
612
+ .setDescription(article.excerpt)
613
+ .setUrl(`https://example.com/article/${article.id}`)
614
+ .setImage(article.coverImage)
615
+ .setSite('@mywebsite')
616
+ .setCreator(article.author.twitter)
617
+
618
+ const html = `
619
+ <!DOCTYPE html>
620
+ <html>
621
+ <head>
622
+ <title>${article.title}</title>
623
+ ${twitter.html()}
624
+ </head>
625
+ <body>
626
+ ${article.content}
627
+ </body>
628
+ </html>
629
+ `
630
+
631
+ res.send(html)
632
+ })
633
+
634
+ // Результат в HTML:
635
+ // <meta property="twitter:card" content="summary_large_image">
636
+ // <meta property="twitter:title" content="Заголовок статьи">
637
+ // <meta property="twitter:description" content="Описание...">
638
+ // <meta property="twitter:url" content="https://example.com/article/123">
639
+ // <meta property="twitter:image" content="https://example.com/images/cover.jpg">
640
+ // <meta property="twitter:site" content="@mywebsite">
641
+ // <meta property="twitter:creator" content="@author">
642
+ ```
643
+
644
+ ### Комбинирование с Open Graph
645
+
646
+ ```javascript
647
+ import { MetaTwitter, MetaOg, MetaTwitterCard, MetaOpenGraphType } from '@dxtmisha/functional'
648
+
649
+ const twitter = new MetaTwitter()
650
+ const og = new MetaOg()
651
+
652
+ // Общая функция обновления
653
+ const updateSocialMeta = (data) => {
654
+ // Twitter Cards
655
+ twitter
656
+ .setCard(MetaTwitterCard.summaryLargeImage)
657
+ .setTitle(data.title)
658
+ .setDescription(data.description)
659
+ .setUrl(data.url)
660
+ .setImage(data.image)
661
+ .setSite(data.twitterSite)
662
+ .setCreator(data.twitterCreator)
663
+
664
+ // Open Graph
665
+ og
666
+ .setType(MetaOpenGraphType.article)
667
+ .setTitle(data.title)
668
+ .setDescription(data.description)
669
+ .setUrl(data.url)
670
+ .setImage(data.image)
671
+ .setSiteName(data.siteName)
672
+ .setLocale('ru_RU')
673
+ }
674
+
675
+ // Использование
676
+ updateSocialMeta({
677
+ title: 'Заголовок статьи',
678
+ description: 'Описание статьи',
679
+ url: 'https://example.com/article/123',
680
+ image: 'https://example.com/images/cover.jpg',
681
+ twitterSite: '@mywebsite',
682
+ twitterCreator: '@author',
683
+ siteName: 'Мой Сайт'
684
+ })
685
+
686
+ // Для SSR - объединенный HTML
687
+ const allSocialMetaHTML = twitter.html() + og.html()
688
+ ```
689
+
690
+ ### Интеграция с CMS
691
+
692
+ ```javascript
693
+ import { MetaTwitter, MetaTwitterCard } from '@dxtmisha/functional'
694
+
695
+ // Функция обновления Twitter Card из CMS данных
696
+ const updateTwitterFromCMS = (pageData) => {
697
+ const twitter = new MetaTwitter()
698
+
699
+ // Определение типа карточки
700
+ const cardMap = {
701
+ 'post': MetaTwitterCard.summaryLargeImage,
702
+ 'news': MetaTwitterCard.summary,
703
+ 'video': MetaTwitterCard.player
704
+ }
705
+
706
+ twitter
707
+ .setCard(cardMap[pageData.contentType] || MetaTwitterCard.summaryLargeImage)
708
+ .setTitle(pageData.seo?.twitterTitle || pageData.title)
709
+ .setDescription(pageData.seo?.twitterDescription || pageData.excerpt)
710
+ .setUrl(pageData.canonicalUrl)
711
+ .setImage(pageData.seo?.twitterImage || pageData.featuredImage)
712
+ .setSite(pageData.site.twitterHandle)
713
+
714
+ // Добавление автора если есть
715
+ if (pageData.author?.twitter) {
716
+ twitter.setCreator(pageData.author.twitter)
717
+ }
718
+
719
+ return twitter
720
+ }
721
+
722
+ // Использование
723
+ const page = await cms.getPage(pageId)
724
+ updateTwitterFromCMS(page)
725
+ ```
726
+
727
+ ### Валидация и отладка
728
+
729
+ ```javascript
730
+ import { MetaTwitter } from '@dxtmisha/functional'
731
+
732
+ const twitter = new MetaTwitter()
733
+
734
+ // Проверка обязательных полей
735
+ const validateTwitterCard = () => {
736
+ const errors = []
737
+
738
+ if (!twitter.getCard()) errors.push('Отсутствует twitter:card')
739
+ if (!twitter.getTitle()) errors.push('Отсутствует twitter:title')
740
+ if (!twitter.getDescription()) errors.push('Отсутствует twitter:description')
741
+ if (!twitter.getImage()) errors.push('Отсутствует twitter:image')
742
+
743
+ // Проверка длины
744
+ if (twitter.getTitle().length > 70) {
745
+ errors.push('twitter:title слишком длинный (>70 символов)')
746
+ }
747
+
748
+ if (twitter.getDescription().length > 200) {
749
+ errors.push('twitter:description слишком длинное (>200 символов)')
750
+ }
751
+
752
+ if (errors.length > 0) {
753
+ console.error('Twitter Card ошибки:', errors)
754
+ }
755
+
756
+ return errors.length === 0
757
+ }
758
+
759
+ // Вывод всех Twitter Card тегов для отладки
760
+ const debugTwitterCard = () => {
761
+ console.group('Twitter Card Tags')
762
+ console.log('Card Type:', twitter.getCard())
763
+ console.log('Title:', twitter.getTitle())
764
+ console.log('Description:', twitter.getDescription())
765
+ console.log('Image:', twitter.getImage())
766
+ console.log('URL:', twitter.getUrl())
767
+ console.log('Site:', twitter.getSite())
768
+ console.log('Creator:', twitter.getCreator())
769
+ console.groupEnd()
770
+ }
771
+
772
+ // Экспорт для тестирования
773
+ const exportTwitterData = () => {
774
+ return twitter.getItems()
775
+ }
776
+
777
+ // Проверка перед публикацией
778
+ const checkBeforePublish = () => {
779
+ const isValid = validateTwitterCard()
780
+
781
+ if (isValid) {
782
+ console.log('✓ Twitter Card настроен правильно')
783
+ } else {
784
+ console.warn('⚠ Twitter Card требует внимания')
785
+ debugTwitterCard()
786
+ }
787
+
788
+ return isValid
789
+ }
790
+ ```
791
+
792
+ ## Рекомендации по использованию
793
+
794
+ ### Обязательные теги
795
+ Для корректного отображения Twitter Card необходимо установить минимум:
796
+ - `twitter:card` — тип карточки
797
+ - `twitter:title` — заголовок
798
+ - `twitter:description` — описание
799
+ - `twitter:image` — изображение
800
+
801
+ ### Размеры изображений
802
+
803
+ **summary карточка:**
804
+ - **Рекомендуемый размер:** 120×120 px (минимум)
805
+ - **Оптимальный размер:** 280×150 px
806
+ - **Соотношение сторон:** 1:1 (квадратное)
807
+
808
+ **summary_large_image карточка:**
809
+ - **Минимальный размер:** 300×157 px
810
+ - **Оптимальный размер:** 1200×628 px (как Open Graph)
811
+ - **Соотношение сторон:** 2:1 или 1.91:1
812
+ - **Максимальный размер файла:** 5 MB
813
+ - **Форматы:** JPG, PNG, WebP, GIF
814
+
815
+ ### Длина текста
816
+ - **twitter:title:** до 70 символов
817
+ - **twitter:description:** до 200 символов
818
+ - **twitter:site:** @username формат
819
+ - **twitter:creator:** @username формат
820
+
821
+ ### Атрибуты @username
822
+ - **twitter:site** — официальный Twitter аккаунт сайта/бренда
823
+ - Показывается как "via @username"
824
+ - Используется для атрибуции сайта
825
+ - **twitter:creator** — Twitter аккаунт автора контента
826
+ - Показывается как "by @username"
827
+ - Используется для атрибуции автора
828
+
829
+ ### Тестирование
830
+ Проверяйте Twitter Card теги с помощью:
831
+ - [Twitter Card Validator](https://cards-dev.twitter.com/validator) (старая версия)
832
+ - Тестируйте, публикуя тестовую ссылку в Twitter
833
+ - Используйте режим предпросмотра при создании твита
834
+
835
+ ### Различия с Open Graph
836
+ Twitter Cards может использовать Open Graph теги как fallback:
837
+ - Если `twitter:title` отсутствует, используется `og:title`
838
+ - Если `twitter:description` отсутствует, используется `og:description`
839
+ - Если `twitter:image` отсутствует, используется `og:image`
840
+
841
+ Однако рекомендуется устанавливать Twitter Card теги явно для лучшего контроля.
842
+
843
+ ## Примечания
844
+
845
+ - Класс наследует все методы от `MetaManager`, включая `html()`, `getItems()`, `setByList()`
846
+ - Автоматически использует атрибут `property` (как и Open Graph)
847
+ - Все изменения немедленно отражаются в DOM дереве
848
+ - При создании экземпляра автоматически считываются существующие Twitter Card теги из страницы
849
+ - Для SSR используйте метод `html()` для генерации мета-тегов в серверном шаблоне
850
+ - Содержимое автоматически экранируется для предотвращения XSS
851
+ - Twitter может кэшировать карточки, используйте Card Validator для сброса кэша
852
+ - Поддерживаются все официальные типы Twitter Cards
853
+