@poveste/app 0.14.0 → 0.16.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.
- package/dist/app/style/main.pcss +18 -44
- package/dist/bundled/App.vue_vue_type_script_setup_true_lang.js +9 -7
- package/dist/bundled/app.css +91 -28
- package/dist/bundled/components/app/AppActions.vue_vue_type_script_setup_true_lang.js +44 -27
- package/dist/bundled/components/app/ShortcutTooltip.js +5 -0
- package/dist/bundled/components/app/ShortcutTooltip.vue_vue_type_script_setup_true_lang.js +27 -0
- package/dist/bundled/components/app/TopBarChipItem.js +1 -1
- package/dist/bundled/components/base/BaseDropdown.js +6 -0
- package/dist/bundled/components/base/BaseDropdown.vue_vue_type_script_setup_true_lang.js +68 -0
- package/dist/bundled/components/base/BaseEmpty.js +2 -2
- package/dist/bundled/components/base/BaseOverflowMenu.vue_vue_type_script_setup_true_lang.js +19 -19
- package/dist/bundled/components/base/BaseSelect.js +1 -0
- package/dist/bundled/components/base/BaseSelect.vue_vue_type_script_setup_true_lang.js +194 -33
- package/dist/bundled/components/base/BaseSplitPane.js +1 -1
- package/dist/bundled/components/base/BaseSplitPane.vue_vue_type_script_setup_true_lang.js +65 -4
- package/dist/bundled/components/command/PromptSelect.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/bundled/components/panel/ControlsComponentPropItem.vue_vue_type_script_setup_true_lang.js +24 -16
- package/dist/bundled/components/panel/ControlsComponentProps.vue_vue_type_script_setup_true_lang.js +9 -6
- package/dist/bundled/components/panel/ControlsComponentState.vue_vue_type_script_setup_true_lang.js +9 -6
- package/dist/bundled/components/panel/PaneTabs.vue_vue_type_script_setup_true_lang.js +6 -6
- package/dist/bundled/components/panel/StatePresets.vue_vue_type_script_setup_true_lang.js +96 -52
- package/dist/bundled/components/panel/StoryEvent.vue_vue_type_script_setup_true_lang.js +5 -5
- package/dist/bundled/components/panel/StorySidePanel.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/bundled/components/panel/StorySourceCode.js +1 -1
- package/dist/bundled/components/panel/StorySourceCode.vue_vue_type_script_setup_true_lang.js +24 -18
- package/dist/bundled/components/search/SearchItemContent.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/bundled/components/search/SearchPane.vue_vue_type_script_setup_true_lang.js +1 -2
- package/dist/bundled/components/story/StoryResponsivePreview.js +1 -1
- package/dist/bundled/components/story/StoryResponsivePreview.vue_vue_type_script_setup_true_lang.js +52 -45
- package/dist/bundled/components/story/StoryVariantGridItem.js +1 -1
- package/dist/bundled/components/story/StoryVariantGridItem.vue_vue_type_script_setup_true_lang.js +22 -20
- package/dist/bundled/components/story/StoryVariantSingle.js +1 -1
- package/dist/bundled/components/story/StoryVariantSingle.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue_vue_type_script_setup_true_lang.js +9 -6
- package/dist/bundled/components/story/StoryView.vue_vue_type_script_setup_true_lang.js +5 -1
- package/dist/bundled/components/toolbar/DevOnlyToolbarOpenInEditor.vue_vue_type_script_setup_true_lang.js +15 -12
- package/dist/bundled/components/toolbar/ToolbarBackground.vue_vue_type_script_setup_true_lang.js +20 -16
- package/dist/bundled/components/toolbar/ToolbarNewTab.vue_vue_type_script_setup_true_lang.js +16 -13
- package/dist/bundled/components/toolbar/ToolbarResponsiveSize.vue_vue_type_script_setup_true_lang.js +35 -24
- package/dist/bundled/components/toolbar/ToolbarTextDirection.vue_vue_type_script_setup_true_lang.js +15 -12
- package/dist/bundled/components/toolbar/ToolbarTitle.js +1 -1
- package/dist/bundled/components/toolbar/ToolbarTitle.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/bundled/components/tree/StoryGroup.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/bundled/components/tree/StoryList.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/bundled/components/tree/StoryListFolder.js +1 -1
- package/dist/bundled/components/tree/StoryListFolder.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/bundled/components/tree/StoryListItem.js +1 -1
- package/dist/bundled/components/tree/StoryListItem.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/bundled/index.js +0 -13
- package/dist/bundled/sandbox.js +5 -3
- package/dist/bundled/stores/story.js +2 -2
- package/dist/bundled/util/commands.js +1 -1
- package/dist/bundled/util/dark.js +1 -1
- package/dist/bundled/util/events.js +1 -1
- package/dist/bundled/util/grid-slots.js +1 -1
- package/dist/bundled/util/icons.generated.js +4 -2
- package/dist/bundled/util/keyboard.js +8 -14
- package/dist/bundled/util/mapping.js +2 -2
- package/dist/bundled/util/render-tracker.js +33 -0
- package/dist/bundled/util/scroll.js +26 -5
- package/dist/bundled/util/state.js +105 -5
- package/dist/bundled/util/variant.js +12 -2
- package/dist/style.css +753 -357
- package/package.json +28 -28
- package/src/__tests__/base-select.spec.ts +25 -0
- package/src/__tests__/render-tracker.spec.ts +38 -0
- package/src/__tests__/reset.spec.ts +53 -0
- package/src/__tests__/state-clone.spec.ts +55 -1
- package/src/__tests__/state-types.spec.ts +175 -0
- package/src/app/App.vue +44 -35
- package/src/app/components/app/AppActions.vue +42 -30
- package/src/app/components/app/ShortcutTooltip.vue +29 -0
- package/src/app/components/app/TopBarChipItem.vue +1 -1
- package/src/app/components/base/BaseDropdown.vue +142 -0
- package/src/app/components/base/BaseEmpty.vue +1 -1
- package/src/app/components/base/BaseListItemLink.vue +4 -2
- package/src/app/components/base/BaseOverflowMenu.vue +27 -21
- package/src/app/components/base/BaseSelect.vue +270 -41
- package/src/app/components/base/BaseSplitPane.vue +75 -4
- package/src/app/components/command/PromptSelect.vue +1 -1
- package/src/app/components/panel/ControlsComponentPropItem.vue +29 -17
- package/src/app/components/panel/ControlsComponentProps.vue +7 -5
- package/src/app/components/panel/ControlsComponentState.vue +7 -5
- package/src/app/components/panel/PaneTabs.vue +6 -6
- package/src/app/components/panel/StatePresets.vue +116 -74
- package/src/app/components/panel/StoryEvent.vue +10 -9
- package/src/app/components/panel/StorySidePanel.vue +2 -1
- package/src/app/components/panel/StorySourceCode.vue +51 -44
- package/src/app/components/search/SearchItemContent.vue +2 -1
- package/src/app/components/search/SearchPane.vue +2 -3
- package/src/app/components/story/StoryResponsivePreview.vue +61 -29
- package/src/app/components/story/StoryVariantGridItem.vue +20 -19
- package/src/app/components/story/StoryVariantSingle.vue +1 -0
- package/src/app/components/story/StoryVariantSinglePreviewRemote.vue +14 -8
- package/src/app/components/story/StoryView.vue +4 -1
- package/src/app/components/toolbar/DevOnlyToolbarOpenInEditor.vue +14 -12
- package/src/app/components/toolbar/ToolbarBackground.vue +22 -23
- package/src/app/components/toolbar/ToolbarNewTab.vue +14 -12
- package/src/app/components/toolbar/ToolbarResponsiveSize.vue +31 -25
- package/src/app/components/toolbar/ToolbarTextDirection.vue +14 -10
- package/src/app/components/toolbar/ToolbarTitle.vue +2 -2
- package/src/app/components/tree/StoryGroup.vue +2 -2
- package/src/app/components/tree/StoryList.vue +2 -2
- package/src/app/components/tree/StoryListFolder.vue +2 -2
- package/src/app/components/tree/StoryListItem.vue +1 -1
- package/src/app/index.ts +0 -17
- package/src/app/sandbox.ts +16 -3
- package/src/app/stores/story.ts +2 -2
- package/src/app/style/main.pcss +18 -44
- package/src/app/types.ts +4 -4
- package/src/app/util/commands.ts +1 -1
- package/src/app/util/dark.ts +1 -1
- package/src/app/util/env.ts +0 -1
- package/src/app/util/events.ts +6 -5
- package/src/app/util/grid-slots.ts +1 -1
- package/src/app/util/icons.generated.ts +2 -2
- package/src/app/util/keyboard.ts +7 -11
- package/src/app/util/mapping.ts +2 -2
- package/src/app/util/render-tracker.ts +31 -0
- package/src/app/util/scroll.ts +47 -9
- package/src/app/util/state.ts +141 -8
- package/src/app/util/variant.ts +12 -2
- package/dist/app/style/floating.pcss +0 -40
- package/dist/bundled/util/tooltip.js +0 -14
- package/src/app/style/floating.pcss +0 -40
- package/src/app/util/tooltip.ts +0 -13
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { HighlighterCore } from 'shiki/core'
|
|
3
3
|
import type { Story, Variant } from '../../types'
|
|
4
4
|
import { Icon } from '@iconify/vue'
|
|
5
|
-
import { HstCopyIcon } from '@poveste/controls'
|
|
5
|
+
import { HstCopyIcon, HstTooltip } from '@poveste/controls'
|
|
6
6
|
import { unindent } from '@poveste/shared'
|
|
7
7
|
import { clientSupportPlugins } from 'virtual:$poveste-support-plugins-client'
|
|
8
8
|
import { computed, markRaw, nextTick, onMounted, ref, shallowRef, watch, watchEffect } from 'vue'
|
|
@@ -58,7 +58,7 @@ watch(() => [props.variant, generateSourceCodeFn.value], async () => {
|
|
|
58
58
|
}
|
|
59
59
|
catch (e) {
|
|
60
60
|
console.error(e)
|
|
61
|
-
error.value = e.message
|
|
61
|
+
error.value = e instanceof Error ? e.message : String(e)
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
// Auto-switch
|
|
@@ -121,8 +121,8 @@ watch(() => props.variant, () => {
|
|
|
121
121
|
|
|
122
122
|
const scroller = ref<HTMLElement>()
|
|
123
123
|
|
|
124
|
-
function onScroll(event) {
|
|
125
|
-
if (sourceHtml.value) {
|
|
124
|
+
function onScroll(event: Event) {
|
|
125
|
+
if (sourceHtml.value && event.target instanceof HTMLElement) {
|
|
126
126
|
lastScroll = event.target.scrollTop
|
|
127
127
|
}
|
|
128
128
|
}
|
|
@@ -151,50 +151,56 @@ watch(sourceHtml, async () => {
|
|
|
151
151
|
|
|
152
152
|
<!-- Display source modes -->
|
|
153
153
|
<div class="flex flex-none gap-px h-full py-2">
|
|
154
|
-
<
|
|
155
|
-
|
|
156
|
-
class="flex items-center gap-1 h-full px-1 bg-gray-500/10 rounded-l transition-all ease-[cubic-bezier(0,1,.6,1)] duration-300 overflow-hidden"
|
|
157
|
-
:class="[
|
|
158
|
-
displayedSource !== 'dynamic' ? 'max-w-6 opacity-70' : 'max-w-[82px] text-primary-800 dark:text-primary-400',
|
|
159
|
-
dynamicSourceCode ? 'cursor-pointer hover:bg-gray-500/30 active:bg-gray-600/50' : 'opacity-50',
|
|
160
|
-
]"
|
|
161
|
-
@click="dynamicSourceCode && (displayedSource = 'dynamic')"
|
|
154
|
+
<HstTooltip
|
|
155
|
+
:content="!dynamicSourceCode ? 'Dynamic source code is not available' : displayedSource !== 'dynamic' ? 'Switch to dynamic source' : null"
|
|
162
156
|
>
|
|
163
|
-
<
|
|
164
|
-
|
|
165
|
-
class="
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
'opacity-0': displayedSource !== 'dynamic',
|
|
171
|
-
}"
|
|
157
|
+
<button
|
|
158
|
+
class="flex items-center gap-1 h-full px-1 bg-gray-500/10 rounded-l transition-all ease-[cubic-bezier(0,1,.6,1)] duration-300 overflow-hidden"
|
|
159
|
+
:class="[
|
|
160
|
+
displayedSource !== 'dynamic' ? 'max-w-6 opacity-70' : 'max-w-[82px] text-primary-800 dark:text-primary-400',
|
|
161
|
+
dynamicSourceCode ? 'cursor-pointer hover:bg-gray-500/30 active:bg-gray-600/50' : displayedSource !== 'dynamic' && 'opacity-50',
|
|
162
|
+
]"
|
|
163
|
+
@click="dynamicSourceCode && (displayedSource = 'dynamic')"
|
|
172
164
|
>
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
165
|
+
<Icon
|
|
166
|
+
icon="carbon:flash"
|
|
167
|
+
class="w-4 h-4 flex-none"
|
|
168
|
+
/>
|
|
169
|
+
<span
|
|
170
|
+
class="transition-opacity duration-300"
|
|
171
|
+
:class="{
|
|
172
|
+
'opacity-0': displayedSource !== 'dynamic',
|
|
173
|
+
}"
|
|
174
|
+
>
|
|
175
|
+
Dynamic
|
|
176
|
+
</span>
|
|
177
|
+
</button>
|
|
178
|
+
</HstTooltip>
|
|
179
|
+
<HstTooltip
|
|
180
|
+
:content="!staticSourceCode ? 'Static source code is not available' : displayedSource !== 'static' ? 'Switch to static source' : null"
|
|
184
181
|
>
|
|
185
|
-
<
|
|
186
|
-
|
|
187
|
-
class="
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
'opacity-0': displayedSource !== 'static',
|
|
193
|
-
}"
|
|
182
|
+
<button
|
|
183
|
+
class="flex items-center gap-1 h-full px-1 bg-gray-500/10 rounded-r transition-all ease-[cubic-bezier(0,1,.6,1)] duration-300 overflow-hidden"
|
|
184
|
+
:class="[
|
|
185
|
+
displayedSource !== 'static' ? 'max-w-6 opacity-70' : 'max-w-[63px] text-primary-800 dark:text-primary-400',
|
|
186
|
+
staticSourceCode ? 'cursor-pointer hover:bg-gray-500/30 active:bg-gray-600/50' : displayedSource !== 'static' && 'opacity-50',
|
|
187
|
+
]"
|
|
188
|
+
@click="staticSourceCode && (displayedSource = 'static')"
|
|
194
189
|
>
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
190
|
+
<Icon
|
|
191
|
+
icon="carbon:document"
|
|
192
|
+
class="w-4 h-4 flex-none"
|
|
193
|
+
/>
|
|
194
|
+
<span
|
|
195
|
+
class="transition-opacity duration-300"
|
|
196
|
+
:class="{
|
|
197
|
+
'opacity-0': displayedSource !== 'static',
|
|
198
|
+
}"
|
|
199
|
+
>
|
|
200
|
+
Static
|
|
201
|
+
</span>
|
|
202
|
+
</button>
|
|
203
|
+
</HstTooltip>
|
|
198
204
|
</div>
|
|
199
205
|
|
|
200
206
|
<HstCopyIcon
|
|
@@ -223,6 +229,7 @@ watch(sourceHtml, async () => {
|
|
|
223
229
|
ref="scroller"
|
|
224
230
|
class="__poveste-code-placeholder w-full h-full p-4 outline-none bg-transparent resize-none m-0"
|
|
225
231
|
:value="displayedSourceCode"
|
|
232
|
+
aria-label="Source code"
|
|
226
233
|
readonly
|
|
227
234
|
data-testid="story-source-code"
|
|
228
235
|
@scroll="onScroll"
|
|
@@ -138,8 +138,7 @@ watch(rateLimitedSearch, async (value) => {
|
|
|
138
138
|
break
|
|
139
139
|
}
|
|
140
140
|
case 'variant': {
|
|
141
|
-
const
|
|
142
|
-
const story = storyStore.getStoryById(storyId)
|
|
141
|
+
const story = storyStore.getStoryById(idMapData.id.replace(/:.*$/s, ''))
|
|
143
142
|
const variant = storyStore.getVariantById(idMapData.id)
|
|
144
143
|
if (!story || !variant) continue
|
|
145
144
|
list.push(variantResultFactory(story, variant, rank))
|
|
@@ -268,7 +267,7 @@ const results = computed<SearchResult[]>(() => {
|
|
|
268
267
|
...commandResults.value,
|
|
269
268
|
...titleResults.value,
|
|
270
269
|
]
|
|
271
|
-
const seen = {}
|
|
270
|
+
const seen: Record<string, boolean> = {}
|
|
272
271
|
for (const r of titleResults.value) {
|
|
273
272
|
seen[r.id] = true
|
|
274
273
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import type { Ref } from 'vue'
|
|
3
3
|
import type { Variant } from '../../types'
|
|
4
4
|
import { Icon } from '@iconify/vue'
|
|
5
|
+
import { HstTooltip } from '@poveste/controls'
|
|
5
6
|
import { useEventListener } from '@vueuse/core'
|
|
6
|
-
import { VTooltip as vTooltip } from 'floating-vue'
|
|
7
7
|
import { computed, onUnmounted, ref } from 'vue'
|
|
8
8
|
import { usePreviewSettingsStore } from '../../stores/preview-settings'
|
|
9
9
|
import CheckerboardPattern from '../misc/CheckerboardPattern.vue'
|
|
@@ -101,7 +101,9 @@ function useDragger(el: Ref<HTMLDivElement | undefined>, value: Ref<number | nul
|
|
|
101
101
|
function onTouchStart(event: TouchEvent) {
|
|
102
102
|
event.preventDefault()
|
|
103
103
|
event.stopPropagation()
|
|
104
|
-
const
|
|
104
|
+
const [touch] = event.touches
|
|
105
|
+
if (!touch) return
|
|
106
|
+
const start = axis === 'x' ? touch.clientX : touch.clientY
|
|
105
107
|
const startValue = startFrom()
|
|
106
108
|
resizing.value = true
|
|
107
109
|
|
|
@@ -112,7 +114,9 @@ function useDragger(el: Ref<HTMLDivElement | undefined>, value: Ref<number | nul
|
|
|
112
114
|
]
|
|
113
115
|
|
|
114
116
|
function onTouchMove(event: TouchEvent) {
|
|
115
|
-
const
|
|
117
|
+
const [touch] = event.touches
|
|
118
|
+
if (!touch) return
|
|
119
|
+
const delta = (axis === 'x' ? touch.clientX : touch.clientY) - start
|
|
116
120
|
value.value = Math.max(min, Math.min(max, startValue + delta))
|
|
117
121
|
}
|
|
118
122
|
|
|
@@ -197,9 +201,18 @@ const sizeTooltip = computed(() => `${responsiveWidth.value ?? 'Auto'} × ${resp
|
|
|
197
201
|
preview would otherwise be shown against the bare box below the
|
|
198
202
|
first screenful. The checkerboard is measured against this for the
|
|
199
203
|
same reason — but the draggers are not, since they belong to the
|
|
200
|
-
visible box rather than to the story's full height.
|
|
204
|
+
visible box rather than to the story's full height.
|
|
205
|
+
`flex`, and `flex-1` rather than `h-full` below, because that is the
|
|
206
|
+
half `min-h-full` costs: a percentage height resolves against a
|
|
207
|
+
parent's *specified* height, and this one's is `auto`. So `h-full`
|
|
208
|
+
collapsed all the way down to the iframe, which then fell back to
|
|
209
|
+
its own default of 150px and clipped every story taller than that
|
|
210
|
+
(#949). A flex child reads the used height instead, which
|
|
211
|
+
`min-height` does give it — and with `min-height: auto` it still
|
|
212
|
+
refuses to shrink below its content, so a tall story pushes this box
|
|
213
|
+
taller exactly as it did. -->
|
|
201
214
|
<div
|
|
202
|
-
class="rounded-lg min-h-full relative"
|
|
215
|
+
class="rounded-lg min-h-full relative flex flex-col"
|
|
203
216
|
:class="responsive ? 'bind-preview-bg' : ''"
|
|
204
217
|
:data-testid="responsive ? 'responsive-preview-bg' : undefined"
|
|
205
218
|
>
|
|
@@ -208,10 +221,17 @@ const sizeTooltip = computed(() => `${responsiveWidth.value ?? 'Auto'} × ${resp
|
|
|
208
221
|
class="absolute inset-0 w-full h-full text-gray-500/20"
|
|
209
222
|
/>
|
|
210
223
|
<div
|
|
211
|
-
class="
|
|
224
|
+
class="flex-1 relative flex flex-col"
|
|
212
225
|
:class="responsive ? 'p-8' : ''"
|
|
213
226
|
>
|
|
214
|
-
|
|
227
|
+
<!-- `grid`, so the one in-flow child stretches to this box without
|
|
228
|
+
asking for a percentage of it. `h-full` here read a height that
|
|
229
|
+
is decided by flex, which Chrome treats as indefinite for
|
|
230
|
+
percentage resolution — the same wall one level up. Stretching
|
|
231
|
+
is not shrinking: the child keeps its `min-height: auto`, so an
|
|
232
|
+
inline story taller than the preview still grows this and the
|
|
233
|
+
box above it (#258). -->
|
|
234
|
+
<div class="w-full flex-1 relative grid">
|
|
215
235
|
<div class="absolute inset-0" />
|
|
216
236
|
|
|
217
237
|
<slot
|
|
@@ -239,31 +259,43 @@ const sizeTooltip = computed(() => `${responsiveWidth.value ?? 'Auto'} × ${resp
|
|
|
239
259
|
|
|
240
260
|
<!-- Resize Dragger -->
|
|
241
261
|
<template v-if="isResponsiveEnabled">
|
|
242
|
-
<
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
class="absolute w-4 top-0 bottom-4 right-0 hover:bg-primary-500/30 flex items-center justify-center cursor-ew-resize group hover:text-primary-500"
|
|
262
|
+
<HstTooltip
|
|
263
|
+
:content="sizeTooltip"
|
|
264
|
+
side="right"
|
|
246
265
|
>
|
|
247
|
-
<
|
|
248
|
-
|
|
249
|
-
class="w-4
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
266
|
+
<div
|
|
267
|
+
ref="horizontalDragger"
|
|
268
|
+
class="absolute w-4 top-0 bottom-4 right-0 hover:bg-primary-500/30 flex items-center justify-center cursor-ew-resize group hover:text-primary-500"
|
|
269
|
+
>
|
|
270
|
+
<Icon
|
|
271
|
+
icon="mdi:drag-vertical-variant"
|
|
272
|
+
class="w-4 h-4 opacity-20 group-hover:opacity-90"
|
|
273
|
+
/>
|
|
274
|
+
</div>
|
|
275
|
+
</HstTooltip>
|
|
276
|
+
<HstTooltip
|
|
277
|
+
:content="sizeTooltip"
|
|
278
|
+
side="bottom"
|
|
256
279
|
>
|
|
257
|
-
<
|
|
258
|
-
|
|
259
|
-
class="
|
|
280
|
+
<div
|
|
281
|
+
ref="verticalDragger"
|
|
282
|
+
class="absolute h-4 left-0 right-4 bottom-0 hover:bg-primary-500/30 flex items-center justify-center cursor-ns-resize group hover:text-primary-500"
|
|
283
|
+
>
|
|
284
|
+
<Icon
|
|
285
|
+
icon="mdi:drag-horizontal-variant"
|
|
286
|
+
class="w-4 h-4 opacity-20 group-hover:opacity-90"
|
|
287
|
+
/>
|
|
288
|
+
</div>
|
|
289
|
+
</HstTooltip>
|
|
290
|
+
<HstTooltip
|
|
291
|
+
:content="sizeTooltip"
|
|
292
|
+
side="bottom"
|
|
293
|
+
>
|
|
294
|
+
<div
|
|
295
|
+
ref="cornerDragger"
|
|
296
|
+
class="absolute w-4 h-4 right-0 bottom-0 hover:bg-primary-500/30 flex items-center justify-center cursor-nwse-resize group hover:text-primary-500"
|
|
260
297
|
/>
|
|
261
|
-
</
|
|
262
|
-
<div
|
|
263
|
-
ref="cornerDragger"
|
|
264
|
-
v-tooltip.bottom="sizeTooltip"
|
|
265
|
-
class="absolute w-4 h-4 right-0 bottom-0 hover:bg-primary-500/30 flex items-center justify-center cursor-nwse-resize group hover:text-primary-500"
|
|
266
|
-
/>
|
|
298
|
+
</HstTooltip>
|
|
267
299
|
</template>
|
|
268
300
|
</div>
|
|
269
301
|
</div>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import type { PropType } from 'vue'
|
|
3
3
|
import type { Story, Variant } from '../../types'
|
|
4
4
|
import { Icon } from '@iconify/vue'
|
|
5
|
-
import { HstCopyIcon } from '@poveste/controls'
|
|
5
|
+
import { HstCopyIcon, HstTooltip } from '@poveste/controls'
|
|
6
6
|
import { useResizeObserver } from '@vueuse/core'
|
|
7
7
|
import { computed, nextTick, ref, toRefs, watch } from 'vue'
|
|
8
8
|
import { useRouter } from 'vue-router'
|
|
@@ -111,28 +111,29 @@ const useIframe = computed(() => {
|
|
|
111
111
|
>
|
|
112
112
|
<!-- Header -->
|
|
113
113
|
<div class="flex-none flex items-center">
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
:class="{
|
|
119
|
-
'hover:bg-gray-200 text-gray-500 dark:hover:bg-gray-800': !isActive,
|
|
120
|
-
'bg-primary-200 hover:bg-primary-300 text-primary-800 dark:bg-primary-700 dark:hover:bg-primary-800 dark:text-primary-200': isActive,
|
|
121
|
-
}"
|
|
122
|
-
>
|
|
123
|
-
<Icon
|
|
124
|
-
:icon="variant.icon ?? 'carbon:cube'"
|
|
125
|
-
class="w-4 h-4 opacity-50"
|
|
114
|
+
<HstTooltip :content="variant.title">
|
|
115
|
+
<RouterLink
|
|
116
|
+
:to="targetRoute"
|
|
117
|
+
class="rounded w-max px-2 py-0.5 min-w-16 cursor-pointer flex items-center gap-1 flex-shrink"
|
|
126
118
|
:class="{
|
|
127
|
-
'text-gray-500': !isActive
|
|
128
|
-
'
|
|
119
|
+
'hover:bg-gray-200 text-gray-500 dark:hover:bg-gray-800': !isActive,
|
|
120
|
+
'bg-primary-200 hover:bg-primary-300 text-primary-800 dark:bg-primary-700 dark:hover:bg-primary-800 dark:text-primary-200': isActive,
|
|
129
121
|
}"
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
>
|
|
123
|
+
<Icon
|
|
124
|
+
:icon="variant.icon ?? 'carbon:cube'"
|
|
125
|
+
class="w-4 h-4 opacity-50"
|
|
126
|
+
:class="{
|
|
127
|
+
'text-gray-500': !isActive && !variant.iconColor,
|
|
128
|
+
'bind-icon-color': !isActive && variant.iconColor,
|
|
129
|
+
}"
|
|
130
|
+
/>
|
|
131
|
+
<span class="truncate flex-1">{{ variant.title }}</span>
|
|
132
|
+
</RouterLink>
|
|
133
|
+
</HstTooltip>
|
|
133
134
|
|
|
134
135
|
<!-- Toolbar -->
|
|
135
|
-
<div class="flex-none ml-auto hidden group-hover:flex items-center">
|
|
136
|
+
<div class="flex-none ml-auto hidden group-hover:flex group-focus-within:flex items-center">
|
|
136
137
|
<HstCopyIcon
|
|
137
138
|
:content="() => getSourceCode(story, variant)"
|
|
138
139
|
/>
|
|
@@ -12,6 +12,7 @@ import { useStoryErrorStore } from '../../stores/story-errors'
|
|
|
12
12
|
import { EVENT_SEND, PREVIEW_SETTINGS_REQUEST, PREVIEW_SETTINGS_SYNC, SANDBOX_HEIGHT, SANDBOX_READY, SANDBOX_RETARGET, STATE_SYNC } from '../../util/const'
|
|
13
13
|
import { firstReportedHeight } from '../../util/grid-cell-height'
|
|
14
14
|
import { trackWindow } from '../../util/keyboard'
|
|
15
|
+
import { createRenderTracker } from '../../util/render-tracker'
|
|
15
16
|
import { getSandboxUrl } from '../../util/sandbox'
|
|
16
17
|
import { toRawDeep } from '../../util/state'
|
|
17
18
|
import { createStateBridge } from '../../util/state-bridge'
|
|
@@ -31,11 +32,7 @@ const errorStore = useStoryErrorStore()
|
|
|
31
32
|
|
|
32
33
|
const storyError = computed(() => errorStore.forVariant(props.story.id, props.variant.id))
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
// render that produced it — otherwise a fixed story stays marked until reload.
|
|
36
|
-
watch(() => [props.story.id, props.variant.id], () => {
|
|
37
|
-
errorStore.clear(props.story.id, props.variant.id)
|
|
38
|
-
})
|
|
35
|
+
const render = createRenderTracker()
|
|
39
36
|
|
|
40
37
|
// Iframe
|
|
41
38
|
|
|
@@ -103,6 +100,8 @@ function fromCurrentOccupant(data: { storyId?: string, variantId?: string }) {
|
|
|
103
100
|
useEventListener(window, 'message', (event) => {
|
|
104
101
|
// With many grid iframes mounted, every sandbox postMessage hits every
|
|
105
102
|
// parent listener. Skip events that didn't originate from this iframe.
|
|
103
|
+
// Paired with the origin check in `sandbox.ts`, which guards the other
|
|
104
|
+
// direction (#379).
|
|
106
105
|
if (event.source !== iframe.value?.contentWindow) return
|
|
107
106
|
switch (event.data?.type) {
|
|
108
107
|
case STATE_SYNC:
|
|
@@ -115,10 +114,15 @@ useEventListener(window, 'message', (event) => {
|
|
|
115
114
|
break
|
|
116
115
|
case SANDBOX_READY:
|
|
117
116
|
if (!fromCurrentOccupant(event.data)) break
|
|
117
|
+
// Last render wins, which is what makes a fixed story stop being marked
|
|
118
|
+
// without a reload. Clearing on the id change instead cleared the pair
|
|
119
|
+
// being navigated *to*, so arriving at a broken story hid its error (#597).
|
|
120
|
+
if (render.wasClean()) errorStore.clear(props.story.id, props.variant.id)
|
|
118
121
|
setPreviewReady()
|
|
119
122
|
break
|
|
120
123
|
case SANDBOX_ERROR:
|
|
121
124
|
if (!fromCurrentOccupant(event.data)) break
|
|
125
|
+
render.threw()
|
|
122
126
|
errorStore.report({
|
|
123
127
|
message: event.data.message,
|
|
124
128
|
stack: event.data.stack,
|
|
@@ -207,6 +211,7 @@ let stopTrackKeyboard: (() => void) | undefined
|
|
|
207
211
|
let unmounted = false
|
|
208
212
|
|
|
209
213
|
function reload(url: string) {
|
|
214
|
+
render.begin()
|
|
210
215
|
retargets = 0
|
|
211
216
|
retargeting.value = false
|
|
212
217
|
clearTimeout(retargetTimer)
|
|
@@ -223,6 +228,7 @@ function reload(url: string) {
|
|
|
223
228
|
}
|
|
224
229
|
|
|
225
230
|
watch(sandboxUrl, (url) => {
|
|
231
|
+
render.begin()
|
|
226
232
|
// A new occupant has agreed to nothing, so neither has this end. Kept as a
|
|
227
233
|
// new bridge rather than a reset so there is one way to be in that state.
|
|
228
234
|
bridge = createStateBridge(postState)
|
|
@@ -285,12 +291,12 @@ function previewStyle(isResponsiveEnabled: boolean, finalWidth: number | null, f
|
|
|
285
291
|
const style: Record<string, string> = {}
|
|
286
292
|
|
|
287
293
|
if (isResponsiveEnabled) {
|
|
288
|
-
if (finalWidth) style
|
|
289
|
-
if (finalHeight) style
|
|
294
|
+
if (finalWidth) style['width'] = `${finalWidth}px`
|
|
295
|
+
if (finalHeight) style['height'] = `${finalHeight}px`
|
|
290
296
|
}
|
|
291
297
|
|
|
292
298
|
if (props.autoHeight) {
|
|
293
|
-
style
|
|
299
|
+
style['height'] = `${Math.min(reportedHeight.value ?? placeholderHeight.value, MAX_AUTO_HEIGHT)}px`
|
|
294
300
|
}
|
|
295
301
|
|
|
296
302
|
return style
|
|
@@ -47,7 +47,9 @@ watch(() => storyStore.currentVariant, (value) => {
|
|
|
47
47
|
watch(() => [storyStore.currentStory, storyStore.currentVariant], () => {
|
|
48
48
|
if (!storyStore.currentVariant && autoSelectsVariant(storyStore.currentStory)) {
|
|
49
49
|
const variant = storyStore.currentStory.lastSelectedVariant ?? storyStore.currentStory.variants[0]
|
|
50
|
-
|
|
50
|
+
if (variant) {
|
|
51
|
+
setVariant(variant.id)
|
|
52
|
+
}
|
|
51
53
|
}
|
|
52
54
|
}, {
|
|
53
55
|
immediate: true,
|
|
@@ -109,6 +111,7 @@ function scrollDocsToTop() {
|
|
|
109
111
|
<BaseSplitPane
|
|
110
112
|
v-else
|
|
111
113
|
:save-id="`story-main-${placement}`"
|
|
114
|
+
label="Resize the preview"
|
|
112
115
|
:orientation="splitOrientation"
|
|
113
116
|
:min="30"
|
|
114
117
|
:max="95"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import { Icon } from '@iconify/vue'
|
|
3
|
+
import { HstTooltip } from '@poveste/controls'
|
|
3
4
|
import { openInEditor } from '../../util/open-in-editor.js'
|
|
4
5
|
import TopBarChipItem from '../app/TopBarChipItem.vue'
|
|
5
6
|
|
|
@@ -10,16 +11,17 @@ defineProps<{
|
|
|
10
11
|
</script>
|
|
11
12
|
|
|
12
13
|
<template>
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
<HstTooltip :content="tooltip">
|
|
15
|
+
<TopBarChipItem
|
|
16
|
+
aria-label="Open story in editor"
|
|
17
|
+
target="_blank"
|
|
18
|
+
class="poveste-toolbar-open-in-editor"
|
|
19
|
+
@click="openInEditor(file)"
|
|
20
|
+
>
|
|
21
|
+
<Icon
|
|
22
|
+
icon="carbon:script-reference"
|
|
23
|
+
class="w-4 h-4"
|
|
24
|
+
/>
|
|
25
|
+
</TopBarChipItem>
|
|
26
|
+
</HstTooltip>
|
|
25
27
|
</template>
|
|
@@ -4,6 +4,7 @@ import { Icon } from '@iconify/vue'
|
|
|
4
4
|
import { usePreviewSettingsStore } from '../../stores/preview-settings'
|
|
5
5
|
import { povesteConfig } from '../../util/config'
|
|
6
6
|
import BaseCheckbox from '../base/BaseCheckbox.vue'
|
|
7
|
+
import BaseDropdown from '../base/BaseDropdown.vue'
|
|
7
8
|
|
|
8
9
|
const previewSettings = usePreviewSettingsStore()
|
|
9
10
|
const settings = previewSettings.currentSettings
|
|
@@ -21,32 +22,30 @@ const showDropdown = showColorScheme || !!povesteConfig.backgroundPresets?.lengt
|
|
|
21
22
|
</script>
|
|
22
23
|
|
|
23
24
|
<template>
|
|
24
|
-
<
|
|
25
|
+
<BaseDropdown
|
|
25
26
|
v-if="showDropdown"
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
side="bottom"
|
|
28
|
+
align="end"
|
|
29
|
+
:align-offset="6"
|
|
30
|
+
tooltip="Preview appearance"
|
|
28
31
|
class="poveste-toolbar-background flex-none"
|
|
29
32
|
data-testid="toolbar-background"
|
|
30
33
|
>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class="w-3 h-3 opacity-40 group-hover:opacity-70"
|
|
45
|
-
/>
|
|
46
|
-
</div>
|
|
47
|
-
</template>
|
|
34
|
+
<button
|
|
35
|
+
class="flex items-center gap-1 px-2.5 py-1.5 hover:bg-white/50 dark:hover:bg-white/10 hover:text-primary-500 dark:hover:text-primary-400 cursor-pointer text-gray-900 dark:text-gray-100 transition-colors group"
|
|
36
|
+
aria-label="Preview appearance"
|
|
37
|
+
>
|
|
38
|
+
<Icon
|
|
39
|
+
icon="carbon:color-palette"
|
|
40
|
+
class="w-4 h-4"
|
|
41
|
+
/>
|
|
42
|
+
<Icon
|
|
43
|
+
icon="carbon:chevron-down"
|
|
44
|
+
class="w-3 h-3 opacity-40 group-hover:opacity-70"
|
|
45
|
+
/>
|
|
46
|
+
</button>
|
|
48
47
|
|
|
49
|
-
<template #popper="{
|
|
48
|
+
<template #popper="{ close }">
|
|
50
49
|
<div
|
|
51
50
|
class="flex flex-col items-stretch"
|
|
52
51
|
data-testid="background-popper"
|
|
@@ -89,7 +88,7 @@ const showDropdown = showColorScheme || !!povesteConfig.backgroundPresets?.lengt
|
|
|
89
88
|
? 'bg-primary-500 hover:bg-primary-600 text-white dark:text-black'
|
|
90
89
|
: 'bg-transparent hover:bg-primary-100 dark:hover:bg-primary-700',
|
|
91
90
|
]"
|
|
92
|
-
@click="previewSettings.setBackgroundColor(option.color);
|
|
91
|
+
@click="previewSettings.setBackgroundColor(option.color);close()"
|
|
93
92
|
>
|
|
94
93
|
<span class="mr-auto">{{ option.label }}</span>
|
|
95
94
|
<template v-if="option.color !== '$checkerboard'">
|
|
@@ -107,5 +106,5 @@ const showDropdown = showColorScheme || !!povesteConfig.backgroundPresets?.lengt
|
|
|
107
106
|
</button>
|
|
108
107
|
</div>
|
|
109
108
|
</template>
|
|
110
|
-
</
|
|
109
|
+
</BaseDropdown>
|
|
111
110
|
</template>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { Story, Variant } from '../../types'
|
|
3
3
|
import { Icon } from '@iconify/vue'
|
|
4
|
+
import { HstTooltip } from '@poveste/controls'
|
|
4
5
|
import { computed } from 'vue'
|
|
5
6
|
import { getSandboxUrl } from '../../util/sandbox'
|
|
6
7
|
import TopBarChipItem from '../app/TopBarChipItem.vue'
|
|
@@ -16,16 +17,17 @@ const sandboxUrl = computed(() => {
|
|
|
16
17
|
</script>
|
|
17
18
|
|
|
18
19
|
<template>
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
<HstTooltip content="Open variant in new tab">
|
|
21
|
+
<TopBarChipItem
|
|
22
|
+
:href="sandboxUrl"
|
|
23
|
+
target="_blank"
|
|
24
|
+
aria-label="Open variant in new tab"
|
|
25
|
+
class="poveste-toolbar-new-tab"
|
|
26
|
+
>
|
|
27
|
+
<Icon
|
|
28
|
+
icon="carbon:launch"
|
|
29
|
+
class="w-4 h-4"
|
|
30
|
+
/>
|
|
31
|
+
</TopBarChipItem>
|
|
32
|
+
</HstTooltip>
|
|
31
33
|
</template>
|