Skip to content

Commit 330aa89

Browse files
committed
fix: pin the sidebar only when necessary
1 parent 32d1d0a commit 330aa89

3 files changed

Lines changed: 66 additions & 6 deletions

File tree

app/components/Package/Sidebar.vue

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<script setup lang="ts">
2+
const window = useWindowSize()
3+
const scroll = useWindowScroll()
4+
const container = useTemplateRef<HTMLDivElement>('container')
5+
const content = useTemplateRef<HTMLDivElement>('content')
6+
const bounds = useElementBounding(content)
7+
8+
const active = computed(() => {
9+
return bounds.height.value > window.height.value
10+
})
11+
12+
const direction = computed((previous = 'up'): string => {
13+
if (!active.value) return previous
14+
return scroll.directions.bottom ? 'down' : scroll.directions.top ? 'up' : previous
15+
})
16+
17+
const offset = computed(() => {
18+
if (!active.value) return 0
19+
if (!container.value) return 0
20+
if (!content.value) return 0
21+
22+
return direction.value === 'down'
23+
? content.value.offsetTop
24+
: container.value.offsetHeight - content.value.offsetTop - content.value.offsetHeight
25+
})
26+
27+
const style = computed(() => {
28+
return direction.value === 'down'
29+
? { paddingBlockStart: `${offset.value}px` }
30+
: { paddingBlockEnd: `${offset.value}px` }
31+
})
32+
</script>
33+
34+
<template>
35+
<div
36+
ref="container"
37+
class="group relative data-[active=true]:flex"
38+
:data-direction="direction"
39+
:data-active="active"
40+
:style="style"
41+
>
42+
<div
43+
ref="content"
44+
class="sticky w-full group-data-[direction=up]:(self-start top-30 xl:top-14) group-data-[direction=down]:(self-end bottom-8)"
45+
>
46+
<slot />
47+
</div>
48+
</div>
49+
</template>

app/pages/package/[[org]]/[name].vue

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,11 +1189,9 @@ onKeyStroke(
11891189
</div>
11901190
</section>
11911191
</section>
1192-
<div class="area-sidebar">
1193-
<!-- Sidebar -->
1194-
<div
1195-
class="sidebar-scroll sticky top-34 space-y-6 sm:space-y-8 min-w-0 overflow-y-auto pe-2.5 lg:(max-h-[calc(100dvh-8.5rem)] overscroll-contain) xl:(top-22 pt-2 max-h-[calc(100dvh-6rem)])"
1196-
>
1192+
1193+
<PackageSidebar class="area-sidebar">
1194+
<div class="flex flex-col gap-4 sm:gap-6 xl:(pt-2)">
11971195
<!-- Team access controls (for scoped packages when connected) -->
11981196
<ClientOnly>
11991197
<PackageAccessControls :package-name="pkg.name" />
@@ -1253,7 +1251,7 @@ onKeyStroke(
12531251
<!-- Maintainers (with admin actions when connected) -->
12541252
<PackageMaintainers :package-name="pkg.name" :maintainers="pkg.maintainers" />
12551253
</div>
1256-
</div>
1254+
</PackageSidebar>
12571255
</article>
12581256

12591257
<!-- Error state -->

test/nuxt/a11y.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ import {
125125
PackageMetricsBadges,
126126
PackagePlaygrounds,
127127
PackageReplacement,
128+
PackageSidebar,
128129
PackageSkeleton,
129130
PackageSkillsCard,
130131
PackageTable,
@@ -1987,6 +1988,18 @@ describe('component accessibility audits', () => {
19871988
})
19881989
})
19891990

1991+
describe('PackageSidebar', () => {
1992+
it('should have no accessibility violations with slot content', async () => {
1993+
const component = await mountSuspended(PackageSidebar, {
1994+
slots: {
1995+
default: () => h('div', 'Sidebar content'),
1996+
},
1997+
})
1998+
const results = await runAxe(component)
1999+
expect(results.violations).toEqual([])
2000+
})
2001+
})
2002+
19902003
describe('PackageSkillsCard', () => {
19912004
it('should have no accessibility violations with skills', async () => {
19922005
const component = await mountSuspended(PackageSkillsCard, {

0 commit comments

Comments
 (0)