@blogmcp/mdx-render-vue 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/dist/_virtual/_plugin-vue_export-helper.js +10 -0
  2. package/dist/_virtual/constants.js +4 -0
  3. package/dist/_virtual/index.js +5 -0
  4. package/dist/_virtual/index2.js +4 -0
  5. package/dist/composables/index.d.ts +11 -0
  6. package/dist/composables/index.js +24 -0
  7. package/dist/composables/useAudioPlayer.d.ts +22 -0
  8. package/dist/composables/useAudioPlayer.js +58 -0
  9. package/dist/composables/useCallout.d.ts +43 -0
  10. package/dist/composables/useCallout.js +71 -0
  11. package/dist/composables/useCodeBlock.d.ts +23 -0
  12. package/dist/composables/useCodeBlock.js +67 -0
  13. package/dist/composables/useGallery.d.ts +37 -0
  14. package/dist/composables/useGallery.js +84 -0
  15. package/dist/composables/useMedia.d.ts +18 -0
  16. package/dist/composables/useMedia.js +9 -0
  17. package/dist/composables/useYouTube.d.ts +31 -0
  18. package/dist/composables/useYouTube.js +32 -0
  19. package/dist/edit/AlertEdit.vue.d.ts +12 -0
  20. package/dist/edit/AlertEdit.vue.js +4 -0
  21. package/dist/edit/AlertEdit.vue2.js +18 -0
  22. package/dist/edit/AudioPlayerEdit.vue.d.ts +3 -0
  23. package/dist/edit/AudioPlayerEdit.vue.js +117 -0
  24. package/dist/edit/AudioPlayerEdit.vue2.js +4 -0
  25. package/dist/edit/BadgeEdit.vue.d.ts +2 -0
  26. package/dist/edit/BadgeEdit.vue.js +4 -0
  27. package/dist/edit/BadgeEdit.vue2.js +13 -0
  28. package/dist/edit/ButtonEdit.vue.d.ts +2 -0
  29. package/dist/edit/ButtonEdit.vue.js +4 -0
  30. package/dist/edit/ButtonEdit.vue2.js +13 -0
  31. package/dist/edit/CalloutEdit.vue.d.ts +13 -0
  32. package/dist/edit/CalloutEdit.vue.js +85 -0
  33. package/dist/edit/CalloutEdit.vue2.js +4 -0
  34. package/dist/edit/CardEdit.vue.d.ts +12 -0
  35. package/dist/edit/CardEdit.vue.js +4 -0
  36. package/dist/edit/CardEdit.vue2.js +18 -0
  37. package/dist/edit/CodeBlockEdit.vue.d.ts +12 -0
  38. package/dist/edit/CodeBlockEdit.vue.js +7 -0
  39. package/dist/edit/CodeBlockEdit.vue2.js +89 -0
  40. package/dist/edit/GalleryEdit.vue.d.ts +3 -0
  41. package/dist/edit/GalleryEdit.vue.js +64 -0
  42. package/dist/edit/GalleryEdit.vue2.js +4 -0
  43. package/dist/edit/IconEdit.vue.d.ts +2 -0
  44. package/dist/edit/IconEdit.vue.js +4 -0
  45. package/dist/edit/IconEdit.vue2.js +13 -0
  46. package/dist/edit/TooltipEdit.vue.d.ts +16 -0
  47. package/dist/edit/TooltipEdit.vue.js +4 -0
  48. package/dist/edit/TooltipEdit.vue2.js +24 -0
  49. package/dist/edit/YouTubeEdit.vue.d.ts +3 -0
  50. package/dist/edit/YouTubeEdit.vue.js +41 -0
  51. package/dist/edit/YouTubeEdit.vue2.js +4 -0
  52. package/dist/edit/index.d.ts +29 -0
  53. package/dist/edit/index.js +35 -0
  54. package/dist/index.d.ts +12 -0
  55. package/dist/index.js +75 -0
  56. package/dist/mdx-render-vue.css +31 -0
  57. package/dist/node_modules/@ark-ui/vue/dist/_virtual/_rolldown/runtime.js +13 -0
  58. package/dist/node_modules/@ark-ui/vue/dist/components/factory.js +35 -0
  59. package/dist/node_modules/@ark-ui/vue/dist/components/presence/use-presence-context.js +6 -0
  60. package/dist/node_modules/@ark-ui/vue/dist/components/presence/use-presence.js +40 -0
  61. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-arrow-tip.js +5 -0
  62. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-arrow-tip.vue_vue_type_script_setup_true_lang.js +21 -0
  63. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-arrow.js +5 -0
  64. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-arrow.vue_vue_type_script_setup_true_lang.js +21 -0
  65. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-content.js +5 -0
  66. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-content.vue_vue_type_script_setup_true_lang.js +25 -0
  67. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-context.js +5 -0
  68. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-context.vue_vue_type_script_setup_true_lang.js +14 -0
  69. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-positioner.js +5 -0
  70. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-positioner.vue_vue_type_script_setup_true_lang.js +23 -0
  71. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-root-provider.js +5 -0
  72. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-root-provider.vue_vue_type_script_setup_true_lang.js +38 -0
  73. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-root.js +5 -0
  74. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-root.vue_vue_type_script_setup_true_lang.js +68 -0
  75. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-trigger.js +5 -0
  76. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip-trigger.vue_vue_type_script_setup_true_lang.js +25 -0
  77. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/tooltip.js +22 -0
  78. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/use-tooltip-context.js +6 -0
  79. package/dist/node_modules/@ark-ui/vue/dist/components/tooltip/use-tooltip.js +36 -0
  80. package/dist/node_modules/@ark-ui/vue/dist/providers/environment/use-environment-context.js +13 -0
  81. package/dist/node_modules/@ark-ui/vue/dist/providers/locale/use-locale-context.js +12 -0
  82. package/dist/node_modules/@ark-ui/vue/dist/utils/clean-props.js +8 -0
  83. package/dist/node_modules/@ark-ui/vue/dist/utils/create-context.js +14 -0
  84. package/dist/node_modules/@ark-ui/vue/dist/utils/dynamic.js +34 -0
  85. package/dist/node_modules/@ark-ui/vue/dist/utils/unref-element.js +8 -0
  86. package/dist/node_modules/@ark-ui/vue/dist/utils/use-forward-expose.js +46 -0
  87. package/dist/node_modules/@ark-ui/vue/dist/utils/use-render-strategy.js +5 -0
  88. package/dist/node_modules/@braintree/sanitize-url/dist/constants.js +20 -0
  89. package/dist/node_modules/@braintree/sanitize-url/dist/index.js +75 -0
  90. package/dist/node_modules/@floating-ui/core/dist/floating-ui.core.js +728 -0
  91. package/dist/node_modules/@floating-ui/dom/dist/floating-ui.dom.js +629 -0
  92. package/dist/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +176 -0
  93. package/dist/node_modules/@floating-ui/utils/dist/floating-ui.utils.js +151 -0
  94. package/dist/node_modules/@iconify/vue/dist/iconify.js +1691 -0
  95. package/dist/node_modules/@zag-js/anatomy/dist/create-anatomy.js +29 -0
  96. package/dist/node_modules/@zag-js/core/dist/create-machine.js +28 -0
  97. package/dist/node_modules/@zag-js/core/dist/merge-props.js +55 -0
  98. package/dist/node_modules/@zag-js/core/dist/scope.js +20 -0
  99. package/dist/node_modules/@zag-js/core/dist/state.js +176 -0
  100. package/dist/node_modules/@zag-js/core/dist/types.js +11 -0
  101. package/dist/node_modules/@zag-js/dom-query/dist/chunk-QZ7TP4HQ.js +6 -0
  102. package/dist/node_modules/@zag-js/dom-query/dist/computed-style.js +11 -0
  103. package/dist/node_modules/@zag-js/dom-query/dist/event.js +37 -0
  104. package/dist/node_modules/@zag-js/dom-query/dist/node.js +64 -0
  105. package/dist/node_modules/@zag-js/dom-query/dist/overflow.js +28 -0
  106. package/dist/node_modules/@zag-js/dom-query/dist/platform.js +23 -0
  107. package/dist/node_modules/@zag-js/dom-query/dist/query.js +6 -0
  108. package/dist/node_modules/@zag-js/dom-query/dist/raf.js +52 -0
  109. package/dist/node_modules/@zag-js/dom-query/dist/set.js +22 -0
  110. package/dist/node_modules/@zag-js/dom-query/dist/shared.js +8 -0
  111. package/dist/node_modules/@zag-js/focus-visible/dist/index.js +159 -0
  112. package/dist/node_modules/@zag-js/popper/dist/get-anchor.js +39 -0
  113. package/dist/node_modules/@zag-js/popper/dist/get-placement.js +296 -0
  114. package/dist/node_modules/@zag-js/popper/dist/get-styles.js +47 -0
  115. package/dist/node_modules/@zag-js/popper/dist/middleware.js +79 -0
  116. package/dist/node_modules/@zag-js/popper/dist/placement.js +7 -0
  117. package/dist/node_modules/@zag-js/presence/dist/presence.connect.js +18 -0
  118. package/dist/node_modules/@zag-js/presence/dist/presence.machine.js +175 -0
  119. package/dist/node_modules/@zag-js/tooltip/dist/tooltip.anatomy.js +7 -0
  120. package/dist/node_modules/@zag-js/tooltip/dist/tooltip.connect.js +155 -0
  121. package/dist/node_modules/@zag-js/tooltip/dist/tooltip.dom.js +24 -0
  122. package/dist/node_modules/@zag-js/tooltip/dist/tooltip.machine.js +416 -0
  123. package/dist/node_modules/@zag-js/tooltip/dist/tooltip.store.js +9 -0
  124. package/dist/node_modules/@zag-js/types/dist/prop-types.js +14 -0
  125. package/dist/node_modules/@zag-js/utils/dist/array.js +7 -0
  126. package/dist/node_modules/@zag-js/utils/dist/equal.js +36 -0
  127. package/dist/node_modules/@zag-js/utils/dist/functions.js +11 -0
  128. package/dist/node_modules/@zag-js/utils/dist/guard.js +26 -0
  129. package/dist/node_modules/@zag-js/utils/dist/object.js +16 -0
  130. package/dist/node_modules/@zag-js/utils/dist/store.js +44 -0
  131. package/dist/node_modules/@zag-js/utils/dist/warning.js +31 -0
  132. package/dist/node_modules/@zag-js/vue/dist/bindable.js +48 -0
  133. package/dist/node_modules/@zag-js/vue/dist/machine.js +258 -0
  134. package/dist/node_modules/@zag-js/vue/dist/normalize-props.js +42 -0
  135. package/dist/node_modules/@zag-js/vue/dist/refs.js +14 -0
  136. package/dist/node_modules/@zag-js/vue/dist/track.js +22 -0
  137. package/dist/node_modules/dompurify/dist/purify.es.js +1190 -0
  138. package/dist/registry.d.ts +76 -0
  139. package/dist/registry.js +164 -0
  140. package/dist/render/alert/Alert.vue.d.ts +18 -0
  141. package/dist/render/alert/Alert.vue.js +4 -0
  142. package/dist/render/alert/Alert.vue2.js +43 -0
  143. package/dist/render/alert/index.d.ts +2 -0
  144. package/dist/render/audioplayer/AudioPlayerDefault.vue.d.ts +3 -0
  145. package/dist/render/audioplayer/AudioPlayerDefault.vue.js +116 -0
  146. package/dist/render/audioplayer/AudioPlayerDefault.vue2.js +4 -0
  147. package/dist/render/audioplayer/index.d.ts +5 -0
  148. package/dist/render/audioplayer/index.js +5 -0
  149. package/dist/render/badge/Badge.vue.d.ts +10 -0
  150. package/dist/render/badge/Badge.vue.js +4 -0
  151. package/dist/render/badge/Badge.vue2.js +28 -0
  152. package/dist/render/badge/index.d.ts +2 -0
  153. package/dist/render/button/Button.vue.d.ts +13 -0
  154. package/dist/render/button/Button.vue.js +4 -0
  155. package/dist/render/button/Button.vue2.js +42 -0
  156. package/dist/render/button/index.d.ts +2 -0
  157. package/dist/render/callout/CalloutDefault.vue.d.ts +13 -0
  158. package/dist/render/callout/CalloutDefault.vue.js +86 -0
  159. package/dist/render/callout/CalloutDefault.vue2.js +4 -0
  160. package/dist/render/callout/CalloutMinimal.vue.d.ts +13 -0
  161. package/dist/render/callout/CalloutMinimal.vue.js +27 -0
  162. package/dist/render/callout/CalloutMinimal.vue2.js +4 -0
  163. package/dist/render/callout/index.d.ts +6 -0
  164. package/dist/render/callout/index.js +7 -0
  165. package/dist/render/card/Card.vue.d.ts +15 -0
  166. package/dist/render/card/Card.vue.js +4 -0
  167. package/dist/render/card/Card.vue2.js +29 -0
  168. package/dist/render/card/index.d.ts +2 -0
  169. package/dist/render/codeblock/CodeBlockDefault.vue.d.ts +12 -0
  170. package/dist/render/codeblock/CodeBlockDefault.vue.js +7 -0
  171. package/dist/render/codeblock/CodeBlockDefault.vue2.js +92 -0
  172. package/dist/render/codeblock/index.d.ts +5 -0
  173. package/dist/render/codeblock/index.js +5 -0
  174. package/dist/render/gallery/GalleryGrid.vue.d.ts +3 -0
  175. package/dist/render/gallery/GalleryGrid.vue.js +125 -0
  176. package/dist/render/gallery/GalleryGrid.vue2.js +4 -0
  177. package/dist/render/gallery/GalleryLightbox.vue.d.ts +16 -0
  178. package/dist/render/gallery/GalleryLightbox.vue.js +7 -0
  179. package/dist/render/gallery/GalleryLightbox.vue2.js +170 -0
  180. package/dist/render/gallery/index.d.ts +6 -0
  181. package/dist/render/gallery/index.js +7 -0
  182. package/dist/render/icon/Icon.vue.d.ts +9 -0
  183. package/dist/render/icon/Icon.vue.js +4 -0
  184. package/dist/render/icon/Icon.vue2.js +25 -0
  185. package/dist/render/icon/index.d.ts +2 -0
  186. package/dist/render/index.d.ts +40 -0
  187. package/dist/render/index.js +63 -0
  188. package/dist/render/tooltip/Tooltip.vue.d.ts +18 -0
  189. package/dist/render/tooltip/Tooltip.vue.js +4 -0
  190. package/dist/render/tooltip/Tooltip.vue2.js +58 -0
  191. package/dist/render/tooltip/index.d.ts +2 -0
  192. package/dist/render/youtube/YouTubeDefault.vue.d.ts +3 -0
  193. package/dist/render/youtube/YouTubeDefault.vue.js +79 -0
  194. package/dist/render/youtube/YouTubeDefault.vue2.js +4 -0
  195. package/dist/render/youtube/index.d.ts +5 -0
  196. package/dist/render/youtube/index.js +5 -0
  197. package/dist/useAudioPlayer.d.ts +22 -0
  198. package/dist/useCallout.d.ts +46 -0
  199. package/dist/useCodeBlock.d.ts +25 -0
  200. package/dist/useGallery.d.ts +44 -0
  201. package/dist/useMedia.d.ts +16 -0
  202. package/dist/useYouTube.d.ts +32 -0
  203. package/package.json +125 -0
  204. package/src/composables/index.ts +16 -0
  205. package/src/composables/useAudioPlayer.ts +84 -0
  206. package/src/composables/useCallout.ts +103 -0
  207. package/src/composables/useCodeBlock.ts +90 -0
  208. package/src/composables/useGallery.ts +143 -0
  209. package/src/composables/useMedia.ts +23 -0
  210. package/src/composables/useYouTube.ts +58 -0
  211. package/src/edit/AlertEdit.vue +9 -0
  212. package/src/edit/AudioPlayerEdit.vue +92 -0
  213. package/src/edit/BadgeEdit.vue +7 -0
  214. package/src/edit/ButtonEdit.vue +10 -0
  215. package/src/edit/CalloutEdit.vue +107 -0
  216. package/src/edit/CardEdit.vue +9 -0
  217. package/src/edit/CodeBlockEdit.vue +76 -0
  218. package/src/edit/GalleryEdit.vue +65 -0
  219. package/src/edit/IconEdit.vue +7 -0
  220. package/src/edit/TooltipEdit.vue +15 -0
  221. package/src/edit/YouTubeEdit.vue +33 -0
  222. package/src/edit/index.ts +32 -0
  223. package/src/index.ts +62 -0
  224. package/src/registry.ts +272 -0
  225. package/src/render/alert/Alert.vue +32 -0
  226. package/src/render/alert/index.ts +2 -0
  227. package/src/render/audioplayer/AudioPlayerDefault.vue +89 -0
  228. package/src/render/audioplayer/index.ts +8 -0
  229. package/src/render/badge/Badge.vue +25 -0
  230. package/src/render/badge/index.ts +2 -0
  231. package/src/render/button/Button.vue +41 -0
  232. package/src/render/button/index.ts +2 -0
  233. package/src/render/callout/CalloutDefault.vue +101 -0
  234. package/src/render/callout/CalloutMinimal.vue +31 -0
  235. package/src/render/callout/index.ts +9 -0
  236. package/src/render/card/Card.vue +15 -0
  237. package/src/render/card/index.ts +2 -0
  238. package/src/render/codeblock/CodeBlockDefault.vue +76 -0
  239. package/src/render/codeblock/index.ts +8 -0
  240. package/src/render/gallery/GalleryGrid.vue +162 -0
  241. package/src/render/gallery/GalleryLightbox.vue +162 -0
  242. package/src/render/gallery/index.ts +9 -0
  243. package/src/render/icon/Icon.vue +22 -0
  244. package/src/render/icon/index.ts +2 -0
  245. package/src/render/index.ts +76 -0
  246. package/src/render/tooltip/Tooltip.vue +35 -0
  247. package/src/render/tooltip/index.ts +2 -0
  248. package/src/render/youtube/YouTubeDefault.vue +72 -0
  249. package/src/render/youtube/index.ts +8 -0
@@ -0,0 +1,58 @@
1
+ /**
2
+ * YouTube Composable
3
+ *
4
+ * Shared logic for YouTube component variants.
5
+ */
6
+
7
+ import { computed } from 'vue'
8
+ import type { YouTubeProps } from '@blogmcp/mdx-schema'
9
+
10
+ /**
11
+ * YouTube embed URL base
12
+ */
13
+ export const YOUTUBE_EMBED_BASE = 'https://www.youtube.com/embed/'
14
+
15
+ /**
16
+ * Default iframe allow attributes
17
+ */
18
+ export const YOUTUBE_IFRAME_ALLOW =
19
+ 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture'
20
+
21
+ /**
22
+ * Composable for YouTube component logic
23
+ */
24
+ export function useYouTube(props: YouTubeProps) {
25
+ const embedUrl = computed(() => `${YOUTUBE_EMBED_BASE}${props.id}`)
26
+
27
+ const iframeTitle = computed(() => props.title || 'YouTube video')
28
+
29
+ const hasTitle = computed(() => !!props.title)
30
+
31
+ /**
32
+ * Get thumbnail URL for the video (useful for lazy loading)
33
+ */
34
+ const thumbnailUrl = computed(() => {
35
+ if (!props.id) return ''
36
+ return `https://img.youtube.com/vi/${props.id}/maxresdefault.jpg`
37
+ })
38
+
39
+ /**
40
+ * Get iframe attributes for the embed
41
+ */
42
+ const iframeAttrs = computed(() => ({
43
+ src: embedUrl.value,
44
+ title: iframeTitle.value,
45
+ frameborder: '0',
46
+ allow: YOUTUBE_IFRAME_ALLOW,
47
+ allowfullscreen: true,
48
+ }))
49
+
50
+ return {
51
+ embedUrl,
52
+ iframeTitle,
53
+ hasTitle,
54
+ thumbnailUrl,
55
+ iframeAttrs,
56
+ YOUTUBE_IFRAME_ALLOW,
57
+ }
58
+ }
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ import Alert from '../render/alert/Alert.vue'
3
+ </script>
4
+
5
+ <template>
6
+ <Alert v-bind="($attrs as any)">
7
+ <slot />
8
+ </Alert>
9
+ </template>
@@ -0,0 +1,92 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * AudioPlayer Edit Component
4
+ *
5
+ * Used in md-editor for previewing audio content.
6
+ * Has dark theme styling optimized for the editor.
7
+ * Shows transcription and summary when showTranscription prop is set.
8
+ */
9
+
10
+ import { useAudioPlayer } from '../composables/useAudioPlayer'
11
+ import type { AudioPlayerProps } from '@blogmcp/mdx-schema'
12
+
13
+ const props = defineProps<AudioPlayerProps>()
14
+
15
+ const {
16
+ audioUrl,
17
+ displayTitle,
18
+ hasTitle,
19
+ showTranscription,
20
+ transcriptionText,
21
+ transcriptionSummary,
22
+ transcriptionLoading,
23
+ transcriptionExpanded,
24
+ toggleTranscription,
25
+ } = useAudioPlayer(props)
26
+ </script>
27
+
28
+ <template>
29
+ <div class="audio-player my-4 rounded-lg bg-vscode-bg-secondary p-4 border border-vscode-border">
30
+ <div class="flex items-center gap-3 mb-3">
31
+ <!-- Audio icon -->
32
+ <svg
33
+ class="w-5 h-5 text-vscode-text-muted flex-shrink-0"
34
+ fill="none"
35
+ stroke="currentColor"
36
+ viewBox="0 0 24 24"
37
+ >
38
+ <path
39
+ stroke-linecap="round"
40
+ stroke-linejoin="round"
41
+ stroke-width="2"
42
+ d="M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"
43
+ />
44
+ </svg>
45
+ <span v-if="hasTitle" class="text-sm text-vscode-text font-medium">
46
+ {{ displayTitle }}
47
+ </span>
48
+ <span v-else class="text-sm text-vscode-text-muted italic">
49
+ {{ slug }}
50
+ </span>
51
+ </div>
52
+ <audio
53
+ :src="audioUrl"
54
+ controls
55
+ preload="metadata"
56
+ class="w-full h-8"
57
+ />
58
+
59
+ <!-- Collapsible transcription (dark theme) -->
60
+ <div v-if="showTranscription" class="mt-3">
61
+ <button
62
+ class="flex items-center gap-2 text-xs text-vscode-text-muted hover:text-vscode-text transition-colors cursor-pointer bg-transparent border-0 p-0"
63
+ @click="toggleTranscription"
64
+ >
65
+ <svg
66
+ class="w-3.5 h-3.5 transition-transform"
67
+ :class="{ 'rotate-90': transcriptionExpanded }"
68
+ fill="none"
69
+ stroke="currentColor"
70
+ viewBox="0 0 24 24"
71
+ >
72
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
73
+ </svg>
74
+ Transcription
75
+ </button>
76
+ <div
77
+ v-if="transcriptionExpanded"
78
+ class="mt-2 p-3 bg-vscode-bg rounded border border-vscode-border text-xs text-vscode-text-muted leading-relaxed max-h-48 overflow-y-auto"
79
+ >
80
+ <p v-if="transcriptionLoading" class="italic opacity-60">Loading transcription...</p>
81
+ <p v-else-if="!transcriptionText" class="italic opacity-60">No transcription available.</p>
82
+ <template v-else>
83
+ <div v-if="transcriptionSummary" class="mb-2 pb-2 border-b border-vscode-border">
84
+ <div class="text-[10px] uppercase tracking-wide opacity-50 mb-0.5">Summary</div>
85
+ <div class="text-vscode-text">{{ transcriptionSummary }}</div>
86
+ </div>
87
+ <div class="whitespace-pre-wrap">{{ transcriptionText }}</div>
88
+ </template>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </template>
@@ -0,0 +1,7 @@
1
+ <script setup lang="ts">
2
+ import Badge from '../render/badge/Badge.vue'
3
+ </script>
4
+
5
+ <template>
6
+ <Badge v-bind="($attrs as any)" />
7
+ </template>
@@ -0,0 +1,10 @@
1
+ <script setup lang="ts">
2
+ // Edit wrapper — md-editor is light-themed so we delegate straight to the
3
+ // render component. Pass-through via $attrs avoids re-declaring the strict
4
+ // union types.
5
+ import Button from '../render/button/Button.vue'
6
+ </script>
7
+
8
+ <template>
9
+ <Button v-bind="($attrs as any)" />
10
+ </template>
@@ -0,0 +1,107 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Callout Edit Component
4
+ *
5
+ * Used in md-editor for editing callout content.
6
+ * Has dark theme styling optimized for the editor.
7
+ */
8
+
9
+ import { useCallout, calloutIconPaths } from '../composables/useCallout'
10
+ import type { CalloutProps } from '@blogmcp/mdx-schema'
11
+
12
+ const props = defineProps<CalloutProps>()
13
+
14
+ const { effectiveType, containerClasses, iconClasses } = useCallout(props)
15
+
16
+ // Get icon path based on type
17
+ const iconPath = calloutIconPaths[
18
+ effectiveType.value === 'info'
19
+ ? 'info-circle'
20
+ : effectiveType.value === 'warning'
21
+ ? 'warning-triangle'
22
+ : effectiveType.value === 'tip'
23
+ ? 'lightbulb'
24
+ : 'alert-circle'
25
+ ]
26
+ </script>
27
+
28
+ <template>
29
+ <div
30
+ class="callout my-4 p-4 rounded-lg border-l-4"
31
+ :class="containerClasses"
32
+ >
33
+ <div class="flex items-start gap-3">
34
+ <!-- Icon -->
35
+ <div class="flex-shrink-0 mt-0.5">
36
+ <!-- Info icon -->
37
+ <svg
38
+ v-if="effectiveType === 'info'"
39
+ class="w-5 h-5"
40
+ :class="iconClasses"
41
+ fill="none"
42
+ stroke="currentColor"
43
+ viewBox="0 0 24 24"
44
+ >
45
+ <path
46
+ stroke-linecap="round"
47
+ stroke-linejoin="round"
48
+ stroke-width="2"
49
+ d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
50
+ />
51
+ </svg>
52
+ <!-- Warning icon -->
53
+ <svg
54
+ v-else-if="effectiveType === 'warning'"
55
+ class="w-5 h-5"
56
+ :class="iconClasses"
57
+ fill="none"
58
+ stroke="currentColor"
59
+ viewBox="0 0 24 24"
60
+ >
61
+ <path
62
+ stroke-linecap="round"
63
+ stroke-linejoin="round"
64
+ stroke-width="2"
65
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
66
+ />
67
+ </svg>
68
+ <!-- Tip icon -->
69
+ <svg
70
+ v-else-if="effectiveType === 'tip'"
71
+ class="w-5 h-5"
72
+ :class="iconClasses"
73
+ fill="none"
74
+ stroke="currentColor"
75
+ viewBox="0 0 24 24"
76
+ >
77
+ <path
78
+ stroke-linecap="round"
79
+ stroke-linejoin="round"
80
+ stroke-width="2"
81
+ d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
82
+ />
83
+ </svg>
84
+ <!-- Danger icon -->
85
+ <svg
86
+ v-else-if="effectiveType === 'danger'"
87
+ class="w-5 h-5"
88
+ :class="iconClasses"
89
+ fill="none"
90
+ stroke="currentColor"
91
+ viewBox="0 0 24 24"
92
+ >
93
+ <path
94
+ stroke-linecap="round"
95
+ stroke-linejoin="round"
96
+ stroke-width="2"
97
+ d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
98
+ />
99
+ </svg>
100
+ </div>
101
+ <!-- Content -->
102
+ <div class="flex-1 text-sm">
103
+ <slot />
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </template>
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ import Card from '../render/card/Card.vue'
3
+ </script>
4
+
5
+ <template>
6
+ <Card v-bind="($attrs as any)">
7
+ <slot />
8
+ </Card>
9
+ </template>
@@ -0,0 +1,76 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * CodeBlock Edit Component
4
+ *
5
+ * Used in md-editor for displaying code blocks with copy functionality.
6
+ * Has dark theme styling optimized for the editor.
7
+ */
8
+
9
+ import { ref } from 'vue'
10
+ import { useCodeBlock } from '../composables/useCodeBlock'
11
+ import type { CodeBlockProps } from '@blogmcp/mdx-schema'
12
+
13
+ const props = defineProps<CodeBlockProps>()
14
+
15
+ defineSlots<{
16
+ default(): unknown
17
+ }>()
18
+
19
+ const { copied, languageLabel, languageClass, copyCode } = useCodeBlock(props)
20
+
21
+ const codeRef = ref<HTMLElement | null>(null)
22
+
23
+ async function handleCopy() {
24
+ if (codeRef.value) {
25
+ await copyCode(codeRef.value.textContent || '')
26
+ }
27
+ }
28
+ </script>
29
+
30
+ <template>
31
+ <div class="code-block my-4 rounded-lg overflow-hidden bg-vscode-sidebar border border-vscode-border">
32
+ <!-- Header -->
33
+ <div class="flex items-center justify-between px-4 py-2 bg-vscode-bg border-b border-vscode-border">
34
+ <div class="flex items-center gap-2">
35
+ <span class="text-xs text-vscode-accent font-medium">
36
+ {{ languageLabel }}
37
+ </span>
38
+ <span v-if="title" class="text-xs text-vscode-text-muted">
39
+ {{ title }}
40
+ </span>
41
+ </div>
42
+ <button
43
+ class="flex items-center gap-1 px-2 py-1 text-xs rounded transition-colors"
44
+ :class="copied ? 'bg-green-600 text-white' : 'hover:bg-vscode-active text-vscode-text-muted hover:text-vscode-text'"
45
+ @click="handleCopy"
46
+ >
47
+ <svg v-if="!copied" class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
49
+ </svg>
50
+ <svg v-else class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
51
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
52
+ </svg>
53
+ {{ copied ? 'Copied!' : 'Copy' }}
54
+ </button>
55
+ </div>
56
+
57
+ <!-- Code Content -->
58
+ <div class="code-block-content p-4 overflow-x-auto">
59
+ <pre class="m-0"><code ref="codeRef" :class="languageClass"><slot /></code></pre>
60
+ </div>
61
+ </div>
62
+ </template>
63
+
64
+ <style scoped>
65
+ .code-block-content pre {
66
+ margin: 0;
67
+ background: transparent;
68
+ }
69
+
70
+ .code-block-content code {
71
+ font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
72
+ font-size: 0.875rem;
73
+ line-height: 1.5;
74
+ color: var(--color-vscode-text);
75
+ }
76
+ </style>
@@ -0,0 +1,65 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Gallery Edit Component
4
+ *
5
+ * Used in md-editor for displaying image galleries.
6
+ * Has dark theme styling optimized for the editor.
7
+ */
8
+
9
+ import { useGallery } from '../composables/useGallery'
10
+ import { useOptimizedImg } from '../composables/useMedia'
11
+ import type { GalleryProps } from '@blogmcp/mdx-schema'
12
+
13
+ const props = defineProps<GalleryProps>()
14
+
15
+ const { gridColsClass, gapClass, tileLayout, getImageSrc, getImageAlt, getImageCaption, isVideo, hasImages } = useGallery(props)
16
+ const ImgTag = useOptimizedImg()
17
+ </script>
18
+
19
+ <template>
20
+ <div
21
+ v-if="hasImages"
22
+ class="gallery not-prose my-4"
23
+ :class="[gridColsClass, gapClass]"
24
+ style="display: grid"
25
+ >
26
+ <div
27
+ v-for="(_, index) in images"
28
+ :key="index"
29
+ class="gallery-item"
30
+ >
31
+ <!-- Tile geometry from `tileLayout` (aspectRatio/fit/position props),
32
+ defaulting to a square object-cover tile — kept identical to the blog
33
+ GalleryGrid so the editor preview is WYSIWYG. Inline styles so a
34
+ consumer's Tailwind purge can't drop them (same reason as display:grid). -->
35
+ <div
36
+ class="gallery-media relative overflow-hidden rounded-lg bg-vscode-sidebar"
37
+ :style="tileLayout.tileStyle"
38
+ >
39
+ <!-- No poster (imported videos 404 → 1×1 GIF → blank); seek to the first
40
+ frame (#t=0.1) over a dark cell so a video never reads as white space. -->
41
+ <video
42
+ v-if="isVideo(index)"
43
+ :src="`${getImageSrc(index)}#t=0.1`"
44
+ controls
45
+ preload="metadata"
46
+ playsinline
47
+ :class="tileLayout.mediaSizeClass"
48
+ :style="tileLayout.mediaStyle"
49
+ />
50
+ <component
51
+ v-else
52
+ :is="ImgTag"
53
+ :src="getImageSrc(index)"
54
+ :alt="getImageAlt(index)"
55
+ sizes="100vw sm:50vw md:33vw lg:299px"
56
+ :class="[tileLayout.mediaSizeClass, 'transition-transform hover:scale-105']"
57
+ :style="tileLayout.mediaStyle"
58
+ />
59
+ </div>
60
+ <p v-if="getImageCaption(index)" class="gallery-description px-2 py-1 text-xs text-vscode-text-muted truncate">
61
+ {{ getImageCaption(index) }}
62
+ </p>
63
+ </div>
64
+ </div>
65
+ </template>
@@ -0,0 +1,7 @@
1
+ <script setup lang="ts">
2
+ import IconComp from '../render/icon/Icon.vue'
3
+ </script>
4
+
5
+ <template>
6
+ <IconComp v-bind="($attrs as any)" />
7
+ </template>
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ // In md-editor, Tooltip's hover behavior isn't useful for previewing — just
3
+ // render the child with the tooltip label as an inline hint beside it so the
4
+ // author can see both. Hover still works at runtime in the rendered blog.
5
+ defineProps<{ label: string; placement?: string }>()
6
+ </script>
7
+
8
+ <template>
9
+ <span class="inline-flex items-center gap-2" data-mdx-component="Tooltip">
10
+ <slot />
11
+ <span class="rounded bg-gray-100 px-1.5 py-0.5 text-xs text-gray-600">
12
+ 💡 {{ label }}
13
+ </span>
14
+ </span>
15
+ </template>
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * YouTube Edit Component
4
+ *
5
+ * Used in md-editor for displaying YouTube embeds.
6
+ * Has dark theme styling optimized for the editor.
7
+ */
8
+
9
+ import { useYouTube } from '../composables/useYouTube'
10
+ import type { YouTubeProps } from '@blogmcp/mdx-schema'
11
+
12
+ const props = defineProps<YouTubeProps>()
13
+
14
+ const { embedUrl, iframeTitle, hasTitle, YOUTUBE_IFRAME_ALLOW } = useYouTube(props)
15
+ </script>
16
+
17
+ <template>
18
+ <div class="youtube-embed my-4">
19
+ <div class="relative w-full" style="padding-bottom: 56.25%">
20
+ <iframe
21
+ :src="embedUrl"
22
+ :title="iframeTitle"
23
+ class="absolute inset-0 w-full h-full rounded-lg"
24
+ frameborder="0"
25
+ :allow="YOUTUBE_IFRAME_ALLOW"
26
+ allowfullscreen
27
+ />
28
+ </div>
29
+ <p v-if="hasTitle" class="text-center text-sm text-vscode-text-muted mt-2">
30
+ {{ title }}
31
+ </p>
32
+ </div>
33
+ </template>
@@ -0,0 +1,32 @@
1
+ /**
2
+ * MDX Edit Components
3
+ *
4
+ * These components are used in the md-editor for editing MDX content.
5
+ * md-editor runs in a light theme, so most edit components simply reuse the
6
+ * render variant — selection chrome is added externally by MdxBlockView.
7
+ */
8
+
9
+ export { default as CalloutEdit } from './CalloutEdit.vue'
10
+ export { default as CodeBlockEdit } from './CodeBlockEdit.vue'
11
+ export { default as GalleryEdit } from './GalleryEdit.vue'
12
+ export { default as YouTubeEdit } from './YouTubeEdit.vue'
13
+ export { default as AudioPlayerEdit } from './AudioPlayerEdit.vue'
14
+ export { default as ButtonEdit } from './ButtonEdit.vue'
15
+ export { default as CardEdit } from './CardEdit.vue'
16
+ export { default as AlertEdit } from './AlertEdit.vue'
17
+ export { default as BadgeEdit } from './BadgeEdit.vue'
18
+ export { default as IconEdit } from './IconEdit.vue'
19
+ export { default as TooltipEdit } from './TooltipEdit.vue'
20
+
21
+ // Re-export as generic names for backward compatibility
22
+ export { default as Callout } from './CalloutEdit.vue'
23
+ export { default as CodeBlock } from './CodeBlockEdit.vue'
24
+ export { default as Gallery } from './GalleryEdit.vue'
25
+ export { default as YouTube } from './YouTubeEdit.vue'
26
+ export { default as AudioPlayer } from './AudioPlayerEdit.vue'
27
+ export { default as Button } from './ButtonEdit.vue'
28
+ export { default as Card } from './CardEdit.vue'
29
+ export { default as Alert } from './AlertEdit.vue'
30
+ export { default as Badge } from './BadgeEdit.vue'
31
+ export { default as Icon } from './IconEdit.vue'
32
+ export { default as Tooltip } from './TooltipEdit.vue'
package/src/index.ts ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @blogmcp/mdx-render-vue
3
+ *
4
+ * Vue renderer for MDX components. Wires the framework-agnostic schema
5
+ * (@blogmcp/mdx-schema) to Vue Single-File Components for both the
6
+ * md-editor edit preview (dark theme) and KB blog (light theme, variants).
7
+ */
8
+
9
+ // Composables (Vue-reactive shared logic)
10
+ export * from './composables'
11
+
12
+ // Edit components (for md-editor)
13
+ export {
14
+ CalloutEdit,
15
+ CodeBlockEdit,
16
+ GalleryEdit,
17
+ YouTubeEdit,
18
+ AudioPlayerEdit,
19
+ // Aliases for backward compatibility
20
+ Callout as EditCallout,
21
+ CodeBlock as EditCodeBlock,
22
+ Gallery as EditGallery,
23
+ YouTube as EditYouTube,
24
+ AudioPlayer as EditAudioPlayer,
25
+ } from './edit'
26
+
27
+ // Render components (for blog)
28
+ export {
29
+ Callout as RenderCallout,
30
+ CalloutDefault,
31
+ CalloutMinimal,
32
+ CodeBlock as RenderCodeBlock,
33
+ CodeBlockDefault,
34
+ Gallery as RenderGallery,
35
+ GalleryGrid,
36
+ YouTube as RenderYouTube,
37
+ YouTubeDefault,
38
+ AudioPlayer as RenderAudioPlayer,
39
+ AudioPlayerDefault,
40
+ getRenderComponent,
41
+ getComponentVariants,
42
+ } from './render'
43
+
44
+ // Default component exports (edit components for backward compatibility)
45
+ export {
46
+ Callout,
47
+ CodeBlock,
48
+ Gallery,
49
+ YouTube,
50
+ AudioPlayer,
51
+ } from './edit'
52
+
53
+ // Registry (metadata + render/edit loaders) + helpers
54
+ export {
55
+ componentRegistry,
56
+ getComponentVariants as getRegistryVariants,
57
+ getRenderComponentAsync,
58
+ getEditComponentAsync,
59
+ getEditorConfig,
60
+ type ComponentRegistration,
61
+ type EditorConfig,
62
+ } from './registry'