Skip to content

Commit 12db799

Browse files
committed
fix story sidebar not being selected on deeplink
1 parent 507cd3d commit 12db799

3 files changed

Lines changed: 47 additions & 2 deletions

File tree

app/components/Storybook/FileTree.vue

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function isNodeActive(node: StorybookFileTree): boolean {
2626
2727
// Build route object for a story
2828
function getStoryRoute(node: StorybookFileTree): RouteLocationRaw {
29-
if (node.type === 'story') {
29+
if (node.type === 'story' && node.storyId) {
3030
return {
3131
name: 'stories',
3232
params: { path: props.basePath },
@@ -36,7 +36,7 @@ function getStoryRoute(node: StorybookFileTree): RouteLocationRaw {
3636
// For directories - navigate to first story in that directory
3737
if (node.type === 'directory') {
3838
const firstStory = getFirstStoryInDirectory(node)
39-
if (firstStory) {
39+
if (firstStory?.storyId) {
4040
return {
4141
name: 'stories',
4242
params: { path: props.basePath },
@@ -69,6 +69,48 @@ function getNodeIcon(node: StorybookFileTree): string {
6969
7070
const { toggleDir, isExpanded, autoExpandAncestors } = useStoryTreeState(props.baseUrl)
7171
72+
const storyRefs = shallowReactive(new Map<string, HTMLElement>())
73+
74+
function setStoryRef(storyId: string | null) {
75+
return (el: Element | { $el?: Element } | null) => {
76+
if (!storyId) return
77+
if (!el) {
78+
storyRefs.delete(storyId)
79+
return
80+
}
81+
const target = '$el' in el ? el.$el : el
82+
if (target instanceof HTMLElement) storyRefs.set(storyId, target)
83+
}
84+
}
85+
86+
function findStoryPath(tree: StorybookFileTree[], storyId: string): string | null {
87+
for (const node of tree) {
88+
if (node.type === 'story' && node.storyId === storyId) return node.path
89+
if (node.type === 'directory' && node.children) {
90+
const found = findStoryPath(node.children, storyId)
91+
if (found) return found
92+
}
93+
}
94+
return null
95+
}
96+
97+
watch(
98+
[() => props.currentStoryId, () => props.tree],
99+
([storyId, tree]) => {
100+
if (!storyId || !tree.length || depth.value !== 0) return
101+
const storyPath = findStoryPath(tree, storyId)
102+
if (!storyPath) return
103+
autoExpandAncestors(storyPath)
104+
nextTick(() => {
105+
const target = storyRefs.get(storyId)
106+
if (target) {
107+
target.scrollIntoView({ block: 'nearest', inline: 'nearest' })
108+
}
109+
})
110+
},
111+
{ immediate: true },
112+
)
113+
72114
// Handle directory click - toggle expansion and navigate to first story
73115
function handleDirectoryClick(node: StorybookFileTree) {
74116
if (node.type !== 'directory') return
@@ -120,6 +162,7 @@ function handleDirectoryClick(node: StorybookFileTree) {
120162
block
121163
:style="{ paddingLeft: `${depth * 12 + 32}px` }"
122164
:classicon="getNodeIcon(node)"
165+
:ref="setStoryRef(node.storyId)"
123166
>
124167
<span class="truncate">{{ node.name }}</span>
125168
</LinkBase>

app/components/Storybook/MobileTreeDrawer.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ watch(isOpen, open => (isLocked.value = open))
5959
<aside
6060
v-if="isOpen"
6161
class="md:hidden fixed inset-y-0 inset-is-0 z-50 w-72 bg-bg-subtle border-ie border-border overflow-y-auto"
62+
data-story-tree-scroll
6263
>
6364
<div
6465
class="sticky top-0 bg-bg-subtle border-b border-border px-4 py-3 flex items-center justify-start"

app/pages/package-stories/[...path].vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ defineOgImageComponent('Default', {
365365
class="w-64 lg:w-72 border-ie border-border shrink-0 hidden md:block bg-bg-subtle sticky top-28 self-start h-[calc(100vh-7rem)] overflow-y-auto"
366366
>
367367
<StorybookFileTree
368+
data-story-tree-scroll
368369
:tree="storybookTree"
369370
:current-story-id="currentStoryId"
370371
:base-url="`/package-stories/${packageName}/v/${version}`"

0 commit comments

Comments
 (0)