@ohos-ports/histoire-app 1.0.0-beta.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 (309) hide show
  1. package/LICENSE +21 -0
  2. package/dist/app/assets/histoire-text-dark.svg +89 -0
  3. package/dist/app/assets/histoire-text.svg +89 -0
  4. package/dist/app/assets/histoire.svg +51 -0
  5. package/dist/app/style/floating.pcss +34 -0
  6. package/dist/app/style/main.pcss +100 -0
  7. package/dist/app/style/sandbox.css +24 -0
  8. package/dist/app/style/transitions.pcss +51 -0
  9. package/dist/bundle-index.js +3 -0
  10. package/dist/bundle-main-dev.js +4 -0
  11. package/dist/bundle-main.js +5 -0
  12. package/dist/bundle-sandbox-dev.js +2 -0
  13. package/dist/bundle-sandbox.js +2 -0
  14. package/dist/bundled/App.vue.js +5 -0
  15. package/dist/bundled/App.vue2.js +167 -0
  16. package/dist/bundled/_virtual/_node-dom-env.js +188 -0
  17. package/dist/bundled/_virtual/_node-dom-polyfill.js +152 -0
  18. package/dist/bundled/_virtual/_plugin-vue_export-helper.js +10 -0
  19. package/dist/bundled/_virtual/histoire-commands.js +8 -0
  20. package/dist/bundled/_virtual/histoire-config.js +42 -0
  21. package/dist/bundled/_virtual/histoire-markdown-files.js +8 -0
  22. package/dist/bundled/_virtual/histoire-search-docs-data.js +11 -0
  23. package/dist/bundled/_virtual/histoire-search-title-data.js +11 -0
  24. package/dist/bundled/_virtual/histoire-stories.js +17 -0
  25. package/dist/bundled/_virtual/histoire-support-plugins-client.js +8 -0
  26. package/dist/bundled/_virtual/histoire-theme.js +8 -0
  27. package/dist/bundled/api.js +12 -0
  28. package/dist/bundled/app.css +116 -0
  29. package/dist/bundled/assets/histoire-text-dark.svg.js +4 -0
  30. package/dist/bundled/assets/histoire-text.svg.js +4 -0
  31. package/dist/bundled/assets/histoire.svg.js +4 -0
  32. package/dist/bundled/components/HomeView.vue.js +5 -0
  33. package/dist/bundled/components/HomeView.vue2.js +66 -0
  34. package/dist/bundled/components/app/AppHeader.vue.js +5 -0
  35. package/dist/bundled/components/app/AppHeader.vue2.js +71 -0
  36. package/dist/bundled/components/app/AppLogo.vue.js +5 -0
  37. package/dist/bundled/components/app/AppLogo.vue2.js +29 -0
  38. package/dist/bundled/components/app/Breadcrumb.vue.js +8 -0
  39. package/dist/bundled/components/app/Breadcrumb.vue2.js +91 -0
  40. package/dist/bundled/components/app/HomeCounter.vue.js +5 -0
  41. package/dist/bundled/components/app/HomeCounter.vue2.js +42 -0
  42. package/dist/bundled/components/app/InitialLoading.vue.js +5 -0
  43. package/dist/bundled/components/app/InitialLoading.vue2.js +51 -0
  44. package/dist/bundled/components/app/MobileOverlay.vue.js +5 -0
  45. package/dist/bundled/components/app/MobileOverlay.vue2.js +45 -0
  46. package/dist/bundled/components/base/BaseButton.vue.js +5 -0
  47. package/dist/bundled/components/base/BaseButton.vue2.js +39 -0
  48. package/dist/bundled/components/base/BaseCheckbox.vue.js +5 -0
  49. package/dist/bundled/components/base/BaseCheckbox.vue2.js +78 -0
  50. package/dist/bundled/components/base/BaseEmpty.vue.js +14 -0
  51. package/dist/bundled/components/base/BaseIcon.vue.js +8 -0
  52. package/dist/bundled/components/base/BaseIcon.vue2.js +29 -0
  53. package/dist/bundled/components/base/BaseKeyboardShortcut.vue.js +5 -0
  54. package/dist/bundled/components/base/BaseKeyboardShortcut.vue2.js +20 -0
  55. package/dist/bundled/components/base/BaseListItem.vue.js +5 -0
  56. package/dist/bundled/components/base/BaseListItem.vue2.js +33 -0
  57. package/dist/bundled/components/base/BaseListItemLink.vue.js +33 -0
  58. package/dist/bundled/components/base/BaseListItemLink.vue2.js +26 -0
  59. package/dist/bundled/components/base/BaseOverflowMenu.vue.js +5 -0
  60. package/dist/bundled/components/base/BaseOverflowMenu.vue2.js +100 -0
  61. package/dist/bundled/components/base/BaseOverflowTab.vue.js +36 -0
  62. package/dist/bundled/components/base/BaseOverflowTab.vue2.js +18 -0
  63. package/dist/bundled/components/base/BaseSelect.vue.js +5 -0
  64. package/dist/bundled/components/base/BaseSelect.vue2.js +77 -0
  65. package/dist/bundled/components/base/BaseSplitPane.vue.js +8 -0
  66. package/dist/bundled/components/base/BaseSplitPane.vue2.js +183 -0
  67. package/dist/bundled/components/base/BaseTab.vue.js +36 -0
  68. package/dist/bundled/components/base/BaseTab.vue2.js +18 -0
  69. package/dist/bundled/components/base/BaseTag.vue.js +13 -0
  70. package/dist/bundled/components/command/CommandPrompts.vue.js +5 -0
  71. package/dist/bundled/components/command/CommandPrompts.vue2.js +91 -0
  72. package/dist/bundled/components/command/CommandPromptsModal.vue.js +5 -0
  73. package/dist/bundled/components/command/CommandPromptsModal.vue2.js +45 -0
  74. package/dist/bundled/components/command/PromptSelect.vue.js +5 -0
  75. package/dist/bundled/components/command/PromptSelect.vue2.js +142 -0
  76. package/dist/bundled/components/command/PromptText.vue.js +5 -0
  77. package/dist/bundled/components/command/PromptText.vue2.js +67 -0
  78. package/dist/bundled/components/misc/CheckerboardPattern.vue.js +40 -0
  79. package/dist/bundled/components/misc/HatchedPattern.vue.js +12 -0
  80. package/dist/bundled/components/panel/ControlsComponentPropItem.vue.js +5 -0
  81. package/dist/bundled/components/panel/ControlsComponentPropItem.vue2.js +72 -0
  82. package/dist/bundled/components/panel/ControlsComponentProps.vue.js +5 -0
  83. package/dist/bundled/components/panel/ControlsComponentProps.vue2.js +45 -0
  84. package/dist/bundled/components/panel/ControlsComponentState.vue.js +5 -0
  85. package/dist/bundled/components/panel/ControlsComponentState.vue2.js +41 -0
  86. package/dist/bundled/components/panel/ControlsComponentStateItem.vue.js +5 -0
  87. package/dist/bundled/components/panel/ControlsComponentStateItem.vue2.js +46 -0
  88. package/dist/bundled/components/panel/PaneTabs.vue.js +5 -0
  89. package/dist/bundled/components/panel/PaneTabs.vue2.js +114 -0
  90. package/dist/bundled/components/panel/StatePresets.vue.js +5 -0
  91. package/dist/bundled/components/panel/StatePresets.vue2.js +193 -0
  92. package/dist/bundled/components/panel/StoryControls.vue.js +5 -0
  93. package/dist/bundled/components/panel/StoryControls.vue2.js +87 -0
  94. package/dist/bundled/components/panel/StoryDocs.vue.js +7 -0
  95. package/dist/bundled/components/panel/StoryDocs.vue2.js +161 -0
  96. package/dist/bundled/components/panel/StoryEvent.vue.js +5 -0
  97. package/dist/bundled/components/panel/StoryEvent.vue2.js +59 -0
  98. package/dist/bundled/components/panel/StoryEvents.vue.js +5 -0
  99. package/dist/bundled/components/panel/StoryEvents.vue2.js +53 -0
  100. package/dist/bundled/components/panel/StorySidePanel.vue.js +5 -0
  101. package/dist/bundled/components/panel/StorySidePanel.vue2.js +83 -0
  102. package/dist/bundled/components/panel/StorySourceCode.vue.js +8 -0
  103. package/dist/bundled/components/panel/StorySourceCode.vue2.js +204 -0
  104. package/dist/bundled/components/search/SearchItem.vue.js +8 -0
  105. package/dist/bundled/components/search/SearchItem.vue2.js +93 -0
  106. package/dist/bundled/components/search/SearchItemContent.vue.js +5 -0
  107. package/dist/bundled/components/search/SearchItemContent.vue2.js +71 -0
  108. package/dist/bundled/components/search/SearchLoading.vue.js +5 -0
  109. package/dist/bundled/components/search/SearchLoading.vue2.js +21 -0
  110. package/dist/bundled/components/search/SearchModal.vue.js +5 -0
  111. package/dist/bundled/components/search/SearchModal.vue2.js +51 -0
  112. package/dist/bundled/components/search/SearchPane.vue.js +5 -0
  113. package/dist/bundled/components/search/SearchPane.vue2.js +272 -0
  114. package/dist/bundled/components/search/search-docs-data.js +11 -0
  115. package/dist/bundled/components/search/search-title-data.js +11 -0
  116. package/dist/bundled/components/story/GenericMountStory.vue.js +5 -0
  117. package/dist/bundled/components/story/GenericMountStory.vue2.js +34 -0
  118. package/dist/bundled/components/story/GenericRenderStory.vue.js +5 -0
  119. package/dist/bundled/components/story/GenericRenderStory.vue2.js +39 -0
  120. package/dist/bundled/components/story/StoryResponsivePreview.vue.js +8 -0
  121. package/dist/bundled/components/story/StoryResponsivePreview.vue2.js +207 -0
  122. package/dist/bundled/components/story/StoryVariantGrid.vue.js +5 -0
  123. package/dist/bundled/components/story/StoryVariantGrid.vue2.js +146 -0
  124. package/dist/bundled/components/story/StoryVariantGridItem.vue.js +8 -0
  125. package/dist/bundled/components/story/StoryVariantGridItem.vue2.js +153 -0
  126. package/dist/bundled/components/story/StoryVariantListItem.vue.js +8 -0
  127. package/dist/bundled/components/story/StoryVariantListItem.vue2.js +55 -0
  128. package/dist/bundled/components/story/StoryVariantSingle.vue.js +8 -0
  129. package/dist/bundled/components/story/StoryVariantSingle.vue2.js +107 -0
  130. package/dist/bundled/components/story/StoryVariantSinglePreviewNative.vue.js +5 -0
  131. package/dist/bundled/components/story/StoryVariantSinglePreviewNative.vue2.js +70 -0
  132. package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue.js +5 -0
  133. package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue2.js +128 -0
  134. package/dist/bundled/components/story/StoryVariantSingleView.vue.js +5 -0
  135. package/dist/bundled/components/story/StoryVariantSingleView.vue2.js +66 -0
  136. package/dist/bundled/components/story/StoryView.vue.js +5 -0
  137. package/dist/bundled/components/story/StoryView.vue2.js +104 -0
  138. package/dist/bundled/components/story/StoryViewer.vue.js +8 -0
  139. package/dist/bundled/components/story/StoryViewer.vue2.js +55 -0
  140. package/dist/bundled/components/toolbar/DevOnlyToolbarOpenInEditor.vue.js +5 -0
  141. package/dist/bundled/components/toolbar/DevOnlyToolbarOpenInEditor.vue2.js +31 -0
  142. package/dist/bundled/components/toolbar/ToolbarBackground.vue.js +8 -0
  143. package/dist/bundled/components/toolbar/ToolbarBackground.vue2.js +98 -0
  144. package/dist/bundled/components/toolbar/ToolbarNewTab.vue.js +5 -0
  145. package/dist/bundled/components/toolbar/ToolbarNewTab.vue2.js +36 -0
  146. package/dist/bundled/components/toolbar/ToolbarResponsiveSize.vue.js +5 -0
  147. package/dist/bundled/components/toolbar/ToolbarResponsiveSize.vue2.js +127 -0
  148. package/dist/bundled/components/toolbar/ToolbarTextDirection.vue.js +5 -0
  149. package/dist/bundled/components/toolbar/ToolbarTextDirection.vue2.js +27 -0
  150. package/dist/bundled/components/toolbar/ToolbarTitle.vue.js +5 -0
  151. package/dist/bundled/components/toolbar/ToolbarTitle.vue2.js +26 -0
  152. package/dist/bundled/components/tree/StoryGroup.vue.js +5 -0
  153. package/dist/bundled/components/tree/StoryGroup.vue2.js +74 -0
  154. package/dist/bundled/components/tree/StoryList.vue.js +5 -0
  155. package/dist/bundled/components/tree/StoryList.vue2.js +41 -0
  156. package/dist/bundled/components/tree/StoryListFolder.vue.js +8 -0
  157. package/dist/bundled/components/tree/StoryListFolder.vue2.js +86 -0
  158. package/dist/bundled/components/tree/StoryListItem.vue.js +8 -0
  159. package/dist/bundled/components/tree/StoryListItem.vue2.js +69 -0
  160. package/dist/bundled/index.js +36 -0
  161. package/dist/bundled/plugin.js +49 -0
  162. package/dist/bundled/router.js +32 -0
  163. package/dist/bundled/sandbox.js +87 -0
  164. package/dist/bundled/stores/command.js +25 -0
  165. package/dist/bundled/stores/events.js +29 -0
  166. package/dist/bundled/stores/folder.js +54 -0
  167. package/dist/bundled/stores/preview-settings.js +19 -0
  168. package/dist/bundled/stores/story.js +43 -0
  169. package/dist/bundled/util/commands.js +57 -0
  170. package/dist/bundled/util/config.js +8 -0
  171. package/dist/bundled/util/const.js +10 -0
  172. package/dist/bundled/util/dark.js +28 -0
  173. package/dist/bundled/util/docs.js +26 -0
  174. package/dist/bundled/util/env.js +4 -0
  175. package/dist/bundled/util/events.js +33 -0
  176. package/dist/bundled/util/keyboard.js +90 -0
  177. package/dist/bundled/util/mapping.js +70 -0
  178. package/dist/bundled/util/open-in-editor.js +7 -0
  179. package/dist/bundled/util/preview-settings.js +21 -0
  180. package/dist/bundled/util/responsive.js +6 -0
  181. package/dist/bundled/util/sandbox.js +11 -0
  182. package/dist/bundled/util/scroll.js +31 -0
  183. package/dist/bundled/util/select.js +28 -0
  184. package/dist/bundled/util/state.js +41 -0
  185. package/dist/bundled/util/tooltip.js +15 -0
  186. package/dist/bundled/util/variant.js +21 -0
  187. package/dist/style.css +2853 -0
  188. package/package.json +62 -0
  189. package/postcss-scope-wrapper.cjs +35 -0
  190. package/postcss.config.cjs +9 -0
  191. package/scripts/copy.mjs +12 -0
  192. package/scripts/watchAndCopy.mjs +15 -0
  193. package/src/app/App.vue +172 -0
  194. package/src/app/api.ts +9 -0
  195. package/src/app/assets/histoire-text-dark.svg +89 -0
  196. package/src/app/assets/histoire-text.svg +89 -0
  197. package/src/app/assets/histoire.svg +51 -0
  198. package/src/app/components/HomeView.vue +61 -0
  199. package/src/app/components/app/AppHeader.vue +65 -0
  200. package/src/app/components/app/AppLogo.vue +25 -0
  201. package/src/app/components/app/Breadcrumb.vue +98 -0
  202. package/src/app/components/app/HomeCounter.vue +39 -0
  203. package/src/app/components/app/InitialLoading.vue +44 -0
  204. package/src/app/components/app/MobileOverlay.vue +33 -0
  205. package/src/app/components/base/BaseButton.vue +33 -0
  206. package/src/app/components/base/BaseCheckbox.vue +76 -0
  207. package/src/app/components/base/BaseCopyIcon.vue +34 -0
  208. package/src/app/components/base/BaseEmpty.vue +21 -0
  209. package/src/app/components/base/BaseIcon.vue +31 -0
  210. package/src/app/components/base/BaseKeyboardShortcut.vue +16 -0
  211. package/src/app/components/base/BaseListItem.vue +30 -0
  212. package/src/app/components/base/BaseListItemLink.vue +56 -0
  213. package/src/app/components/base/BaseOverflowMenu.vue +119 -0
  214. package/src/app/components/base/BaseOverflowTab.vue +47 -0
  215. package/src/app/components/base/BaseSelect.vue +75 -0
  216. package/src/app/components/base/BaseSplitPane.vue +244 -0
  217. package/src/app/components/base/BaseTab.vue +47 -0
  218. package/src/app/components/base/BaseTag.vue +5 -0
  219. package/src/app/components/command/CommandPrompts.vue +95 -0
  220. package/src/app/components/command/CommandPromptsModal.vue +41 -0
  221. package/src/app/components/command/PromptSelect.vue +142 -0
  222. package/src/app/components/command/PromptText.vue +65 -0
  223. package/src/app/components/misc/CheckerboardPattern.vue +32 -0
  224. package/src/app/components/misc/HatchedPattern.vue +13 -0
  225. package/src/app/components/panel/ControlsComponentPropItem.vue +73 -0
  226. package/src/app/components/panel/ControlsComponentProps.vue +34 -0
  227. package/src/app/components/panel/ControlsComponentState.vue +38 -0
  228. package/src/app/components/panel/ControlsComponentStateItem.vue +44 -0
  229. package/src/app/components/panel/PaneTabs.vue +84 -0
  230. package/src/app/components/panel/StatePresets.vue +199 -0
  231. package/src/app/components/panel/StoryControls.vue +97 -0
  232. package/src/app/components/panel/StoryDocs.vue +202 -0
  233. package/src/app/components/panel/StoryEvent.vue +54 -0
  234. package/src/app/components/panel/StoryEvents.vue +48 -0
  235. package/src/app/components/panel/StorySidePanel.vue +76 -0
  236. package/src/app/components/panel/StorySourceCode.vue +248 -0
  237. package/src/app/components/search/SearchItem.vue +89 -0
  238. package/src/app/components/search/SearchItemContent.vue +67 -0
  239. package/src/app/components/search/SearchLoading.vue +16 -0
  240. package/src/app/components/search/SearchModal.vue +44 -0
  241. package/src/app/components/search/SearchPane.vue +319 -0
  242. package/src/app/components/search/search-docs-data.ts +9 -0
  243. package/src/app/components/search/search-title-data.ts +9 -0
  244. package/src/app/components/search/types.ts +4 -0
  245. package/src/app/components/story/GenericMountStory.vue +35 -0
  246. package/src/app/components/story/GenericRenderStory.vue +41 -0
  247. package/src/app/components/story/StoryResponsivePreview.vue +216 -0
  248. package/src/app/components/story/StoryVariantGrid.vue +169 -0
  249. package/src/app/components/story/StoryVariantGridItem.vue +163 -0
  250. package/src/app/components/story/StoryVariantListItem.vue +52 -0
  251. package/src/app/components/story/StoryVariantSingle.vue +105 -0
  252. package/src/app/components/story/StoryVariantSinglePreviewNative.vue +66 -0
  253. package/src/app/components/story/StoryVariantSinglePreviewRemote.vue +143 -0
  254. package/src/app/components/story/StoryVariantSingleView.vue +61 -0
  255. package/src/app/components/story/StoryView.vue +110 -0
  256. package/src/app/components/story/StoryViewer.vue +52 -0
  257. package/src/app/components/toolbar/DevOnlyToolbarOpenInEditor.vue +23 -0
  258. package/src/app/components/toolbar/ToolbarBackground.vue +81 -0
  259. package/src/app/components/toolbar/ToolbarNewTab.vue +29 -0
  260. package/src/app/components/toolbar/ToolbarResponsiveSize.vue +82 -0
  261. package/src/app/components/toolbar/ToolbarTextDirection.vue +19 -0
  262. package/src/app/components/toolbar/ToolbarTitle.vue +21 -0
  263. package/src/app/components/tree/StoryGroup.vue +73 -0
  264. package/src/app/components/tree/StoryList.vue +35 -0
  265. package/src/app/components/tree/StoryListFolder.vue +88 -0
  266. package/src/app/components/tree/StoryListItem.vue +72 -0
  267. package/src/app/index.ts +33 -0
  268. package/src/app/plugin.ts +59 -0
  269. package/src/app/router.ts +29 -0
  270. package/src/app/sandbox.ts +101 -0
  271. package/src/app/stores/command.ts +26 -0
  272. package/src/app/stores/events.ts +36 -0
  273. package/src/app/stores/folder.ts +63 -0
  274. package/src/app/stores/preview-settings.ts +18 -0
  275. package/src/app/stores/story.ts +47 -0
  276. package/src/app/style/floating.pcss +34 -0
  277. package/src/app/style/main.pcss +100 -0
  278. package/src/app/style/sandbox.css +24 -0
  279. package/src/app/style/transitions.pcss +51 -0
  280. package/src/app/types.ts +72 -0
  281. package/src/app/util/commands.ts +57 -0
  282. package/src/app/util/config.ts +5 -0
  283. package/src/app/util/const.ts +4 -0
  284. package/src/app/util/dark.ts +27 -0
  285. package/src/app/util/docs.ts +27 -0
  286. package/src/app/util/env.ts +1 -0
  287. package/src/app/util/events.ts +31 -0
  288. package/src/app/util/keyboard.ts +103 -0
  289. package/src/app/util/mapping.ts +80 -0
  290. package/src/app/util/open-in-editor.ts +3 -0
  291. package/src/app/util/preview-settings.ts +23 -0
  292. package/src/app/util/responsive.ts +3 -0
  293. package/src/app/util/sandbox.ts +9 -0
  294. package/src/app/util/scroll.ts +32 -0
  295. package/src/app/util/select.ts +30 -0
  296. package/src/app/util/state.ts +45 -0
  297. package/src/app/util/tooltip.ts +13 -0
  298. package/src/app/util/variant.ts +21 -0
  299. package/src/bundle-index.js +1 -0
  300. package/src/bundle-main-dev.js +4 -0
  301. package/src/bundle-main.js +5 -0
  302. package/src/bundle-sandbox-dev.js +2 -0
  303. package/src/bundle-sandbox.js +2 -0
  304. package/src/index.ts +1 -0
  305. package/src/shim.d.ts +10 -0
  306. package/src/virtual.d.ts +7 -0
  307. package/tailwind.config.cjs +137 -0
  308. package/tsconfig.json +53 -0
  309. package/vite.config.ts +88 -0
@@ -0,0 +1,169 @@
1
+ <script lang="ts" setup>
2
+ import { useResizeObserver } from '@vueuse/core'
3
+ import { computed, onMounted, ref, watch } from 'vue'
4
+ import { useStoryStore } from '../../stores/story'
5
+ import { isMobile } from '../../util/responsive'
6
+ import DevOnlyToolbarOpenInEditor from '../toolbar/DevOnlyToolbarOpenInEditor.vue'
7
+ import ToolbarBackground from '../toolbar/ToolbarBackground.vue'
8
+ import ToolbarTextDirection from '../toolbar/ToolbarTextDirection.vue'
9
+ import StoryVariantGridItem from './StoryVariantGridItem.vue'
10
+
11
+ const storyStore = useStoryStore()
12
+
13
+ const gridTemplateWidth = computed(() => {
14
+ if (storyStore.currentStory.layout.type !== 'grid') {
15
+ return
16
+ }
17
+
18
+ const layoutWidth = storyStore.currentStory.layout.width
19
+
20
+ if (!layoutWidth) {
21
+ return '200px'
22
+ }
23
+
24
+ if (typeof layoutWidth === 'number') {
25
+ return `${layoutWidth}px`
26
+ }
27
+
28
+ return layoutWidth
29
+ })
30
+
31
+ const margin = 16
32
+ const gap = 16
33
+
34
+ const itemWidth = ref(16)
35
+ const maxItemHeight = ref(0)
36
+ const maxCount = ref(10)
37
+ const countPerRow = ref(0)
38
+ const visibleRows = ref(0)
39
+
40
+ const el = ref<HTMLDivElement>(null)
41
+
42
+ useResizeObserver(el, () => {
43
+ updateMaxCount()
44
+ updateSize()
45
+ })
46
+
47
+ function updateMaxCount() {
48
+ if (!maxItemHeight.value) return
49
+
50
+ const width = el.value!.clientWidth - margin * 2
51
+ const height = el.value!.clientHeight
52
+ const scrollTop = el.value!.scrollTop
53
+
54
+ // width = (countPerRow - 1) * gap + countPerRow * itemWidth.value
55
+
56
+ // W = (C - 1) * G + C * I
57
+ // W = C * G - G + C * I
58
+ // W + G = C * G + C * I
59
+ // W + G = C * (G + I)
60
+ // (W + G) / (G + I) = C
61
+
62
+ countPerRow.value = Math.floor((width + gap) / (itemWidth.value + gap))
63
+ visibleRows.value = Math.ceil((height + scrollTop + gap) / (maxItemHeight.value + gap))
64
+ const newMaxCount = countPerRow.value * visibleRows.value
65
+ if (maxCount.value < newMaxCount) {
66
+ maxCount.value = newMaxCount
67
+ }
68
+
69
+ if (storyStore.currentVariant) {
70
+ const index = storyStore.currentStory.variants.indexOf(storyStore.currentVariant)
71
+ if (index + 1 > maxCount.value) {
72
+ maxCount.value = index + 1
73
+ }
74
+ }
75
+ }
76
+
77
+ function onItemResize(w: number, h: number) {
78
+ itemWidth.value = w
79
+ if (maxItemHeight.value < h) {
80
+ maxItemHeight.value = h
81
+ updateMaxCount()
82
+ }
83
+ }
84
+
85
+ watch(() => storyStore.currentVariant, () => {
86
+ maxItemHeight.value = 0 // Reset max height
87
+ updateMaxCount()
88
+ })
89
+
90
+ // Grid size
91
+
92
+ const gridEl = ref<HTMLDivElement>(null)
93
+ const gridColumnWidth = ref(1)
94
+ const viewWidth = ref(1)
95
+
96
+ function updateSize() {
97
+ if (!el.value) return
98
+ viewWidth.value = el.value.clientWidth
99
+
100
+ if (!gridEl.value) return
101
+
102
+ if (gridTemplateWidth.value.endsWith('%')) {
103
+ gridColumnWidth.value = viewWidth.value * Number.parseInt(gridTemplateWidth.value) / 100 - gap
104
+ }
105
+ else {
106
+ gridColumnWidth.value = Number.parseInt(gridTemplateWidth.value)
107
+ }
108
+ }
109
+
110
+ onMounted(() => {
111
+ updateSize()
112
+ })
113
+
114
+ useResizeObserver(gridEl, () => {
115
+ updateSize()
116
+ })
117
+
118
+ const columnCount = computed(() => Math.min(storyStore.currentStory.variants.length, Math.floor((viewWidth.value + gap) / (gridColumnWidth.value + gap))))
119
+ </script>
120
+
121
+ <template>
122
+ <div class="histoire-story-variant-grid htw-flex htw-flex-col htw-items-stretch htw-h-full __histoire-pane-shadow-from-right">
123
+ <!-- Toolbar -->
124
+ <div
125
+ v-if="!isMobile"
126
+ class="htw-flex-none htw-flex htw-items-center htw-justify-end htw-h-8 htw-mx-2 htw-mt-1"
127
+ >
128
+ <ToolbarBackground />
129
+ <ToolbarTextDirection />
130
+
131
+ <DevOnlyToolbarOpenInEditor
132
+ v-if="__HISTOIRE_DEV__"
133
+ :file="storyStore.currentStory.file?.filePath"
134
+ tooltip="Edit story in editor"
135
+ />
136
+ </div>
137
+
138
+ <div
139
+ ref="el"
140
+ class="htw-overflow-y-auto htw-flex htw-flex-1"
141
+ @scroll="updateMaxCount()"
142
+ >
143
+ <div class="htw-flex htw-w-0 htw-flex-1 htw-mx-4">
144
+ <div
145
+ class="htw-m-auto"
146
+ :style="{
147
+ minHeight: `${(storyStore.currentStory.variants.length / countPerRow) * (maxItemHeight + gap) - gap}px`,
148
+ }"
149
+ >
150
+ <div
151
+ ref="gridEl"
152
+ class="htw-grid htw-gap-4 htw-my-4"
153
+ :style="{
154
+ gridTemplateColumns: `repeat(${columnCount}, ${gridColumnWidth}px)`,
155
+ }"
156
+ >
157
+ <StoryVariantGridItem
158
+ v-for="(variant, index) of storyStore.currentStory.variants.slice(0, maxCount)"
159
+ :key="index"
160
+ :variant="variant"
161
+ :story="storyStore.currentStory"
162
+ @resize="onItemResize"
163
+ />
164
+ </div>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ </template>
@@ -0,0 +1,163 @@
1
+ <script lang="ts" setup>
2
+ import type { PropType } from 'vue'
3
+ import type { Story, Variant } from '../../types'
4
+ import { HstCopyIcon } from '@histoire/controls'
5
+ import { Icon } from '@iconify/vue'
6
+ import { useResizeObserver } from '@vueuse/core'
7
+ import { computed, ref, toRefs } from 'vue'
8
+ import { useRouter } from 'vue-router'
9
+ import { usePreviewSettingsStore } from '../../stores/preview-settings'
10
+ import { histoireConfig } from '../../util/config'
11
+ import { isDark } from '../../util/dark'
12
+ import { getSourceCode } from '../../util/docs'
13
+ import { getContrastColor } from '../../util/preview-settings'
14
+ import { useScrollOnActive } from '../../util/scroll'
15
+ import { useCurrentVariantRoute } from '../../util/variant'
16
+ import CheckerboardPattern from '../misc/CheckerboardPattern.vue'
17
+ import ToolbarNewTab from '../toolbar/ToolbarNewTab.vue'
18
+ import GenericRenderStory from './GenericRenderStory.vue'
19
+
20
+ const props = defineProps({
21
+ variant: {
22
+ type: Object as PropType<Variant>,
23
+ required: true,
24
+ },
25
+
26
+ story: {
27
+ type: Object as PropType<Story>,
28
+ required: true,
29
+ },
30
+ })
31
+
32
+ const emit = defineEmits({
33
+ resize: (_width: number, _height: number) => true,
34
+ })
35
+
36
+ const { variant } = toRefs(props)
37
+ const { isActive, targetRoute } = useCurrentVariantRoute(variant)
38
+
39
+ Object.assign(props.variant, {
40
+ previewReady: false,
41
+ })
42
+ function onReady() {
43
+ Object.assign(props.variant, {
44
+ previewReady: true,
45
+ })
46
+ }
47
+
48
+ const router = useRouter()
49
+
50
+ function selectVariant() {
51
+ router.push(targetRoute.value)
52
+ }
53
+
54
+ const el = ref<HTMLDivElement>()
55
+
56
+ const { autoScroll } = useScrollOnActive(isActive, el)
57
+
58
+ useResizeObserver(el, () => {
59
+ if (props.variant.previewReady) {
60
+ emit('resize', el.value!.clientWidth, el.value!.clientHeight)
61
+ if (isActive.value) {
62
+ autoScroll()
63
+ }
64
+ }
65
+ })
66
+
67
+ const settings = usePreviewSettingsStore().currentSettings
68
+
69
+ const contrastColor = computed(() => getContrastColor(settings))
70
+ const autoApplyContrastColor = computed(() => !!histoireConfig.autoApplyContrastColor)
71
+ </script>
72
+
73
+ <template>
74
+ <div
75
+ ref="el"
76
+ class="histoire-story-variant-grid-item htw-cursor-default htw-flex htw-flex-col htw-gap-y-1 htw-group"
77
+ >
78
+ <!-- Header -->
79
+ <div class="htw-flex-none htw-flex htw-items-center">
80
+ <RouterLink
81
+ v-tooltip="variant.title"
82
+ :to="targetRoute"
83
+ class="htw-rounded htw-w-max htw-px-2 htw-py-0.5 htw-min-w-16 htw-cursor-pointer htw-flex htw-items-center htw-gap-1 htw-flex-shrink"
84
+ :class="{
85
+ 'hover:htw-bg-gray-200 htw-text-gray-500 dark:hover:htw-bg-gray-800': !isActive,
86
+ 'htw-bg-primary-200 hover:htw-bg-primary-300 htw-text-primary-800 dark:htw-bg-primary-700 dark:hover:htw-bg-primary-800 dark:htw-text-primary-200': isActive,
87
+ }"
88
+ >
89
+ <Icon
90
+ :icon="variant.icon ?? 'carbon:cube'"
91
+ class="htw-w-4 htw-h-4 htw-opacity-50"
92
+ :class="{
93
+ 'htw-text-gray-500': !isActive && !variant.iconColor,
94
+ 'bind-icon-color': !isActive && variant.iconColor,
95
+ }"
96
+ />
97
+ <span class="htw-truncate htw-flex-1">{{ variant.title }}</span>
98
+ </RouterLink>
99
+
100
+ <!-- Toolbar -->
101
+ <div class="htw-flex-none htw-ml-auto htw-hidden group-hover:htw-flex htw-items-center">
102
+ <HstCopyIcon
103
+ :content="() => getSourceCode(story, variant)"
104
+ />
105
+ <ToolbarNewTab
106
+ :variant="variant"
107
+ :story="story"
108
+ />
109
+ </div>
110
+ </div>
111
+
112
+ <!-- Body -->
113
+ <div
114
+ class="htw-border htw-bg-white dark:htw-bg-gray-700 htw-rounded htw-flex-1 htw-p-4 htw-relative"
115
+ :class="{
116
+ 'htw-border-gray-100 dark:htw-border-gray-800': !isActive,
117
+ 'htw-border-primary-200 dark:htw-border-primary-900': isActive,
118
+ }"
119
+ data-test-id="sandbox-render"
120
+ @click.stop="selectVariant()"
121
+ @keyup="selectVariant()"
122
+ >
123
+ <div
124
+ class="htw-absolute htw-inset-0 htw-rounded bind-preview-bg"
125
+ data-test-id="responsive-preview-bg"
126
+ />
127
+
128
+ <CheckerboardPattern
129
+ v-if="settings.checkerboard"
130
+ class="htw-absolute htw-inset-0 htw-w-full htw-h-full htw-text-gray-500/20"
131
+ />
132
+
133
+ <div
134
+ class="htw-relative htw-h-full"
135
+ :style="{
136
+ '--histoire-contrast-color': contrastColor,
137
+ 'color': autoApplyContrastColor ? contrastColor : undefined,
138
+ }"
139
+ >
140
+ <GenericRenderStory
141
+ :key="`${story.id}-${variant.id}`"
142
+ :variant="variant"
143
+ :story="story"
144
+ :dir="settings.textDirection"
145
+ :class="{
146
+ [histoireConfig.theme.darkClass]: isDark,
147
+ }"
148
+ @ready="onReady"
149
+ />
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </template>
154
+
155
+ <style scoped>
156
+ .bind-icon-color {
157
+ color: v-bind('variant.iconColor');
158
+ }
159
+
160
+ .bind-preview-bg {
161
+ background-color: v-bind('settings.backgroundColor');
162
+ }
163
+ </style>
@@ -0,0 +1,52 @@
1
+ <script lang="ts" setup>
2
+ import type { PropType } from 'vue'
3
+ import type { Variant } from '../../types'
4
+ import { Icon } from '@iconify/vue'
5
+ import { ref, toRefs } from 'vue'
6
+ import { useScrollOnActive } from '../../util/scroll'
7
+ import { useCurrentVariantRoute } from '../../util/variant'
8
+ import BaseListItemLink from '../base/BaseListItemLink.vue'
9
+
10
+ const props = defineProps({
11
+ variant: {
12
+ type: Object as PropType<Variant>,
13
+ required: true,
14
+ },
15
+ })
16
+
17
+ const { variant } = toRefs(props)
18
+ const { isActive, targetRoute } = useCurrentVariantRoute(variant)
19
+ const el = ref<HTMLDivElement>()
20
+ useScrollOnActive(isActive, el)
21
+ </script>
22
+
23
+ <template>
24
+ <div
25
+ ref="el"
26
+ class="histoire-story-variant-list-item"
27
+ data-test-id="story-variant-list-item"
28
+ >
29
+ <BaseListItemLink
30
+ v-slot="{ active }"
31
+ :to="targetRoute"
32
+ :is-active="isActive"
33
+ class="htw-px-2 htw-py-2 md:htw-py-1.5 htw-m-1 htw-rounded-sm htw-flex htw-items-center htw-gap-2"
34
+ >
35
+ <Icon
36
+ :icon="variant.icon ?? 'carbon:cube'"
37
+ class="htw-w-5 htw-h-5 sm:htw-w-4 sm:htw-h-4 htw-flex-none"
38
+ :class="{
39
+ 'htw-text-gray-500': !active && !variant.iconColor,
40
+ 'bind-icon-color': !active && variant.iconColor,
41
+ }"
42
+ />
43
+ <span class="htw-truncate">{{ variant.title }}</span>
44
+ </BaseListItemLink>
45
+ </div>
46
+ </template>
47
+
48
+ <style scoped>
49
+ .bind-icon-color {
50
+ color: v-bind('variant.iconColor');
51
+ }
52
+ </style>
@@ -0,0 +1,105 @@
1
+ <script lang="ts" setup>
2
+ import { Icon } from '@iconify/vue'
3
+ import { computed } from 'vue'
4
+ import { useStoryStore } from '../../stores/story'
5
+ import { isMobile } from '../../util/responsive'
6
+ import BaseSplitPane from '../base/BaseSplitPane.vue'
7
+ import StoryVariantListItem from './StoryVariantListItem.vue'
8
+ import StoryVariantSingleView from './StoryVariantSingleView.vue'
9
+
10
+ defineEmits({
11
+ openVariantMenu: () => true,
12
+ })
13
+
14
+ const storyStore = useStoryStore()
15
+
16
+ const hasSingleVariant = computed(() => (storyStore.currentStory?.variants.length === 1))
17
+
18
+ const variant = computed(() => storyStore.currentVariant)
19
+ </script>
20
+
21
+ <template>
22
+ <div
23
+ v-if="hasSingleVariant && variant"
24
+ class="histoire-story-variant-single htw-p-2 htw-h-full __histoire-pane-shadow-from-right"
25
+ >
26
+ <StoryVariantSingleView
27
+ :variant="variant"
28
+ :story="storyStore.currentStory"
29
+ />
30
+ </div>
31
+ <template v-else>
32
+ <div
33
+ v-if="isMobile"
34
+ class="htw-divide-y htw-divide-gray-100 dark:htw-divide-gray-800 htw-h-full htw-flex htw-flex-col"
35
+ >
36
+ <a
37
+ class="htw-px-6 htw-h-12 hover:htw-text-primary-500 dark:hover:htw-text-primary-400 htw-cursor-pointer htw-flex htw-gap-2 htw-flex-wrap htw-w-full htw-items-center htw-flex-none"
38
+ @click="$emit('openVariantMenu')"
39
+ >
40
+ <template v-if="variant">
41
+ <Icon
42
+ :icon="variant.icon ?? 'carbon:cube'"
43
+ class="htw-w-5 htw-h-5 htw-flex-none"
44
+ :class="{
45
+ 'htw-text-gray-500': !variant.iconColor,
46
+ 'bind-icon-color': variant.iconColor,
47
+ }"
48
+ />
49
+ {{ variant.title }}
50
+ </template>
51
+ <template v-else>
52
+ Select a variant...
53
+ </template>
54
+
55
+ <Icon
56
+ icon="carbon:chevron-sort"
57
+ class="htw-w-5 htw-h-5 htw-shrink-0 htw-ml-auto"
58
+ />
59
+ </a>
60
+ <div
61
+ v-if="storyStore.currentVariant"
62
+ class="htw-p-2 htw-h-full"
63
+ >
64
+ <StoryVariantSingleView
65
+ :variant="storyStore.currentVariant"
66
+ :story="storyStore.currentStory"
67
+ />
68
+ </div>
69
+ </div>
70
+ <BaseSplitPane
71
+ v-else
72
+ save-id="story-single-main-split"
73
+ :min="5"
74
+ :max="40"
75
+ :default-split="17"
76
+ >
77
+ <template #first>
78
+ <div class="htw-h-full htw-overflow-y-auto">
79
+ <StoryVariantListItem
80
+ v-for="(v, index) of storyStore.currentStory.variants"
81
+ :key="index"
82
+ :variant="v"
83
+ />
84
+ </div>
85
+ </template>
86
+ <template #last>
87
+ <div
88
+ v-if="storyStore.currentVariant"
89
+ class="htw-p-2 htw-h-full __histoire-pane-shadow-from-right"
90
+ >
91
+ <StoryVariantSingleView
92
+ :variant="storyStore.currentVariant"
93
+ :story="storyStore.currentStory"
94
+ />
95
+ </div>
96
+ </template>
97
+ </BaseSplitPane>
98
+ </template>
99
+ </template>
100
+
101
+ <style scoped>
102
+ .bind-icon-color {
103
+ color: v-bind('variant?.iconColor');
104
+ }
105
+ </style>
@@ -0,0 +1,66 @@
1
+ <script lang="ts" setup>
2
+ import type { Story, Variant } from '../../types'
3
+ import { computed } from 'vue'
4
+ import { usePreviewSettingsStore } from '../../stores/preview-settings'
5
+ import { histoireConfig } from '../../util/config'
6
+ import { isDark } from '../../util/dark'
7
+ import { getContrastColor } from '../../util/preview-settings'
8
+ import GenericRenderStory from './GenericRenderStory.vue'
9
+ import StoryResponsivePreview from './StoryResponsivePreview.vue'
10
+
11
+ const props = defineProps<{
12
+ story: Story
13
+ variant: Variant
14
+ }>()
15
+
16
+ Object.assign(props.variant, {
17
+ previewReady: false,
18
+ })
19
+
20
+ function onReady() {
21
+ Object.assign(props.variant, {
22
+ previewReady: true,
23
+ })
24
+ }
25
+
26
+ const settings = usePreviewSettingsStore().currentSettings
27
+
28
+ const contrastColor = computed(() => getContrastColor(settings))
29
+ const autoApplyContrastColor = computed(() => !!histoireConfig.autoApplyContrastColor)
30
+ </script>
31
+
32
+ <template>
33
+ <StoryResponsivePreview
34
+ v-slot="{ isResponsiveEnabled, finalWidth, finalHeight }"
35
+ class="histoire-story-variant-single-preview-native"
36
+ :variant="variant"
37
+ >
38
+ <div
39
+ :style="[
40
+ isResponsiveEnabled ? {
41
+ width: finalWidth ? `${finalWidth}px` : '100%',
42
+ height: finalHeight ? `${finalHeight}px` : '100%',
43
+ } : { width: '100%', height: '100%' },
44
+ {
45
+ '--histoire-contrast-color': contrastColor,
46
+ 'color': autoApplyContrastColor ? contrastColor : undefined,
47
+ },
48
+ ]"
49
+ class="htw-relative"
50
+ data-test-id="sandbox-render"
51
+ >
52
+ <GenericRenderStory
53
+ :key="`${story.id}-${variant.id}`"
54
+ :variant="variant"
55
+ :story="story"
56
+ class="htw-h-full"
57
+ :class="{
58
+ [histoireConfig.sandboxDarkClass]: isDark, // @TODO remove
59
+ [histoireConfig.theme.darkClass]: isDark,
60
+ }"
61
+ :dir="settings.textDirection"
62
+ @ready="onReady"
63
+ />
64
+ </div>
65
+ </StoryResponsivePreview>
66
+ </template>
@@ -0,0 +1,143 @@
1
+ <script lang="ts" setup>
2
+ import type { HstEvent } from '../../stores/events'
3
+ import type { Story, Variant } from '../../types'
4
+ import { applyState } from '@histoire/shared'
5
+ import { useEventListener } from '@vueuse/core'
6
+ import { computed, ref, toRaw, watch } from 'vue'
7
+ import { useEventsStore } from '../../stores/events'
8
+ import { usePreviewSettingsStore } from '../../stores/preview-settings'
9
+ import { EVENT_SEND, PREVIEW_SETTINGS_SYNC, SANDBOX_READY, STATE_SYNC } from '../../util/const'
10
+ import { getSandboxUrl } from '../../util/sandbox'
11
+ import { toRawDeep } from '../../util/state'
12
+ import StoryResponsivePreview from './StoryResponsivePreview.vue'
13
+
14
+ const props = defineProps<{
15
+ story: Story
16
+ variant: Variant
17
+ }>()
18
+
19
+ const settings = usePreviewSettingsStore().currentSettings
20
+
21
+ // Iframe
22
+
23
+ const iframe = ref<HTMLIFrameElement>()
24
+
25
+ function syncState() {
26
+ if (iframe.value && props.variant.previewReady) {
27
+ iframe.value.contentWindow.postMessage({
28
+ type: STATE_SYNC,
29
+ state: toRawDeep(props.variant.state, true),
30
+ })
31
+ }
32
+ }
33
+
34
+ let synced = false
35
+
36
+ watch(() => props.variant.state, () => {
37
+ if (synced) {
38
+ synced = false
39
+ return
40
+ }
41
+ syncState()
42
+ }, {
43
+ deep: true,
44
+ immediate: true,
45
+ })
46
+
47
+ Object.assign(props.variant, {
48
+ previewReady: false,
49
+ })
50
+
51
+ useEventListener(window, 'message', (event) => {
52
+ switch (event.data.type) {
53
+ case STATE_SYNC:
54
+ updateVariantState(event.data.state)
55
+ break
56
+ case EVENT_SEND:
57
+ logEvent(event.data.event)
58
+ break
59
+ case SANDBOX_READY:
60
+ setPreviewReady()
61
+ break
62
+ }
63
+ })
64
+
65
+ function updateVariantState(state: any) {
66
+ synced = true
67
+ applyState(props.variant.state, state)
68
+ }
69
+
70
+ function logEvent(event: HstEvent) {
71
+ const eventsStore = useEventsStore()
72
+ eventsStore.addEvent(event)
73
+ }
74
+
75
+ function setPreviewReady() {
76
+ Object.assign(props.variant, {
77
+ previewReady: true,
78
+ })
79
+ }
80
+
81
+ const sandboxUrl = computed(() => {
82
+ return getSandboxUrl(props.story, props.variant)
83
+ })
84
+
85
+ const isIframeLoaded = ref(false)
86
+
87
+ watch(sandboxUrl, () => {
88
+ isIframeLoaded.value = false
89
+ Object.assign(props.variant, {
90
+ previewReady: false,
91
+ })
92
+ })
93
+
94
+ // Settings
95
+
96
+ function syncSettings() {
97
+ if (iframe.value) {
98
+ iframe.value.contentWindow.postMessage({
99
+ type: PREVIEW_SETTINGS_SYNC,
100
+ settings: toRaw(settings),
101
+ })
102
+ }
103
+ }
104
+
105
+ watch(() => settings, () => {
106
+ syncSettings()
107
+ }, {
108
+ deep: true,
109
+ immediate: true,
110
+ })
111
+
112
+ // Iframe load
113
+
114
+ function onIframeLoad() {
115
+ isIframeLoaded.value = true
116
+ syncState()
117
+ syncSettings()
118
+ }
119
+ </script>
120
+
121
+ <template>
122
+ <StoryResponsivePreview
123
+ v-slot="{ isResponsiveEnabled, finalWidth, finalHeight, resizing }"
124
+ class="histoire-story-variant-single-preview-remote"
125
+ :variant="variant"
126
+ >
127
+ <iframe
128
+ ref="iframe"
129
+ :src="sandboxUrl"
130
+ class="htw-w-full htw-h-full htw-relative"
131
+ :class="{
132
+ 'htw-invisible': !isIframeLoaded,
133
+ 'htw-pointer-events-none': resizing,
134
+ }"
135
+ :style="isResponsiveEnabled ? {
136
+ width: finalWidth ? `${finalWidth}px` : null,
137
+ height: finalHeight ? `${finalHeight}px` : null,
138
+ } : undefined"
139
+ data-test-id="preview-iframe"
140
+ @load="onIframeLoad()"
141
+ />
142
+ </StoryResponsivePreview>
143
+ </template>