Skip to content

Commit 08cacfb

Browse files
committed
feat: update package header ui
1 parent 06b5b05 commit 08cacfb

4 files changed

Lines changed: 662 additions & 680 deletions

File tree

app/components/Link/Base.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const keyboardShortcutsEnabled = useKeyboardShortcuts()
124124
<kbd
125125
v-if="keyboardShortcutsEnabled && ariaKeyshortcuts"
126126
data-kbd-hint
127-
class="ms-2 inline-flex items-center justify-center size-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
127+
class="ms-2 hidden sm:inline-flex items-center justify-center size-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
128128
aria-hidden="true"
129129
>
130130
{{ ariaKeyshortcuts }}

app/components/Package/Header.vue

Lines changed: 118 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const props = defineProps<{
1515
provenanceStatus: string
1616
docsLink: RouteLocationRaw | null
1717
codeLink: RouteLocationRaw | null
18-
isBinaryOnly: boolean
18+
page: 'docs' | 'code' | 'diff'
1919
}>()
2020
2121
const { requestedVersion, orgName } = usePackageRoute()
@@ -151,21 +151,17 @@ const likeAction = async () => {
151151

152152
<template>
153153
<!-- Package header -->
154-
<header
155-
class="sticky top-14 z-1 bg-bg py-2 border-border"
156-
ref="header"
157-
:class="[$style.packageHeader, { 'border-b': isHeaderPinned }]"
158-
>
154+
<header class="bg-bg pt-2">
159155
<!-- Package name and version -->
160-
<div class="flex items-baseline gap-x-2 gap-y-1 sm:gap-x-3 flex-wrap min-w-0">
156+
<div class="flex items-baseline justify-between gap-x-2 gap-y-1 flex-wrap min-w-0">
161157
<CopyToClipboardButton
162158
:copied="copiedPkgName"
163159
:copy-text="$t('package.copy_name')"
164160
class="flex flex-col items-start min-w-0"
165161
@click="copyPkgName()"
166162
>
167163
<h1
168-
class="font-mono text-2xl sm:text-3xl font-medium min-w-0 break-words"
164+
class="font-mono text-lg sm:text-3xl font-medium min-w-0 break-words"
169165
:title="pkg?.name"
170166
dir="ltr"
171167
>
@@ -178,84 +174,8 @@ const likeAction = async () => {
178174
</span>
179175
</h1>
180176
</CopyToClipboardButton>
181-
182-
<CopyToClipboardButton
183-
v-if="resolvedVersion"
184-
:copied="copiedVersion"
185-
:copy-text="$t('package.copy_version')"
186-
class="inline-flex items-baseline gap-1.5 font-mono text-base sm:text-lg text-fg-muted shrink-0"
187-
@click="copyVersion()"
188-
>
189-
<!-- Version resolution indicator (e.g., "latest → 4.2.0") -->
190-
<template v-if="requestedVersion && resolvedVersion !== requestedVersion">
191-
<span class="font-mono text-fg-muted text-sm" dir="ltr">{{ requestedVersion }}</span>
192-
<span class="i-lucide:arrow-right rtl-flip w-3 h-3" aria-hidden="true" />
193-
</template>
194-
195-
<LinkBase
196-
v-if="requestedVersion && resolvedVersion !== requestedVersion"
197-
:to="packageRoute(packageName, resolvedVersion)"
198-
:title="$t('package.view_permalink')"
199-
dir="ltr"
200-
>{{ resolvedVersion }}</LinkBase
201-
>
202-
<span dir="ltr" v-else>v{{ resolvedVersion }}</span>
203-
204-
<template v-if="hasProvenance(displayVersion)">
205-
<TooltipApp
206-
:text="
207-
provenanceData && provenanceStatus !== 'pending'
208-
? $t('package.provenance_section.built_and_signed_on', {
209-
provider: provenanceData.providerLabel,
210-
})
211-
: $t('package.verified_provenance')
212-
"
213-
position="bottom"
214-
strategy="fixed"
215-
>
216-
<LinkBase
217-
variant="button-secondary"
218-
size="small"
219-
to="#provenance"
220-
:aria-label="$t('package.provenance_section.view_more_details')"
221-
classicon="i-lucide:shield-check"
222-
/>
223-
</TooltipApp>
224-
</template>
225-
<span
226-
v-if="requestedVersion && latestVersion && resolvedVersion !== latestVersion.version"
227-
class="text-fg-subtle text-sm shrink-0"
228-
>{{ $t('package.not_latest') }}</span
229-
>
230-
</CopyToClipboardButton>
231-
232-
<!-- Docs + Code + Compare — inline on desktop, floating bottom bar on mobile -->
233-
<ButtonGroup
234-
v-if="resolvedVersion"
235-
as="nav"
236-
:aria-label="$t('package.navigation')"
237-
class="hidden sm:flex max-sm:flex max-sm:fixed max-sm:z-40 max-sm:inset-is-1/2 max-sm:-translate-x-1/2 max-sm:rtl:translate-x-1/2 max-sm:bg-[--bg]/90 max-sm:backdrop-blur-md max-sm:border max-sm:border-border max-sm:rounded-md max-sm:shadow-md ms-auto"
238-
:style="navExtraOffsetStyle"
239-
:class="$style.packageNav"
240-
>
241-
<LinkBase
242-
variant="button-secondary"
243-
v-if="docsLink"
244-
:to="docsLink"
245-
aria-keyshortcuts="d"
246-
classicon="i-lucide:file-text"
247-
>
248-
<span class="max-sm:sr-only">{{ $t('package.links.docs') }}</span>
249-
</LinkBase>
250-
<LinkBase
251-
v-if="codeLink"
252-
variant="button-secondary"
253-
:to="codeLink"
254-
aria-keyshortcuts="."
255-
classicon="i-lucide:code"
256-
>
257-
<span class="max-sm:sr-only">{{ $t('package.links.code') }}</span>
258-
</LinkBase>
177+
<!-- Package metrics -->
178+
<div class="flex gap-2 flex-wrap items-stretch">
259179
<LinkBase
260180
variant="button-secondary"
261181
:to="{ name: 'compare', query: { packages: packageName } }"
@@ -264,35 +184,6 @@ const likeAction = async () => {
264184
>
265185
<span class="max-sm:sr-only">{{ $t('package.links.compare') }}</span>
266186
</LinkBase>
267-
<LinkBase
268-
v-if="displayVersion && latestVersion && displayVersion.version !== latestVersion.version"
269-
variant="button-secondary"
270-
:to="diffRoute(packageName, displayVersion.version, latestVersion.version)"
271-
classicon="i-lucide:diff"
272-
:title="$t('compare.compare_versions_title')"
273-
>
274-
<span class="max-sm:sr-only">{{ $t('compare.compare_versions') }}</span>
275-
</LinkBase>
276-
<ButtonBase
277-
v-if="showScrollToTop"
278-
variant="secondary"
279-
:aria-label="$t('common.scroll_to_top')"
280-
@click="scrollToTop"
281-
classicon="i-lucide:arrow-up"
282-
class="sm:p-2.75"
283-
/>
284-
</ButtonGroup>
285-
286-
<!-- Package metrics -->
287-
<div class="basis-full flex gap-2 sm:gap-3 flex-wrap items-stretch">
288-
<PackageMetricsBadges
289-
v-if="resolvedVersion"
290-
:package-name="packageName"
291-
:version="resolvedVersion"
292-
:is-binary="isBinaryOnly"
293-
class="self-baseline"
294-
/>
295-
296187
<!-- Package likes -->
297188
<TooltipApp
298189
:text="
@@ -308,7 +199,7 @@ const likeAction = async () => {
308199
>
309200
<ButtonBase
310201
@click="likeAction"
311-
size="small"
202+
size="medium"
312203
:aria-label="
313204
likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')
314205
"
@@ -330,6 +221,117 @@ const likeAction = async () => {
330221
</div>
331222
</div>
332223
</header>
224+
<div
225+
ref="header"
226+
class="bg-bg sticky top-14 z-1 border-b border-border flex flex-col md:flex-row-reverse items-baseline justify-between gap-x-2 gap-y-1 flex-wrap min-w-0 pt-2"
227+
:class="[$style.packageHeader]"
228+
>
229+
<div
230+
class="flex items-center max-md:justify-between max-md:w-full max-md:flex-row-reverse gap-2"
231+
>
232+
<ButtonBase
233+
variant="secondary"
234+
:aria-label="$t('common.scroll_to_top')"
235+
@click="scrollToTop"
236+
classicon="i-lucide:arrow-up"
237+
:class="showScrollToTop ? '' : 'opacity-0 pointer-events-none select-none'"
238+
class="py-1.5 px-2.5 sm:me-2"
239+
:tabindex="showScrollToTop ? 0 : -1"
240+
/>
241+
<div class="break-all font-mono text-fg-muted">
242+
<template v-if="hasProvenance(displayVersion)">
243+
<TooltipApp
244+
:text="
245+
provenanceData && provenanceStatus !== 'pending'
246+
? $t('package.provenance_section.built_and_signed_on', {
247+
provider: provenanceData.providerLabel,
248+
})
249+
: $t('package.verified_provenance')
250+
"
251+
position="bottom"
252+
strategy="fixed"
253+
>
254+
<LinkBase
255+
variant="button-secondary"
256+
to="#provenance"
257+
:aria-label="$t('package.provenance_section.view_more_details')"
258+
classicon="i-lucide:shield-check"
259+
class="py-1.5 px-2.5 me-2"
260+
/>
261+
</TooltipApp>
262+
</template>
263+
<!-- Version resolution indicator (e.g., "latest → 4.2.0") -->
264+
<template v-if="requestedVersion && resolvedVersion !== requestedVersion">
265+
<TooltipApp
266+
:text="requestedVersion"
267+
position="bottom"
268+
strategy="fixed"
269+
class="vertical-middle"
270+
>
271+
<span class="i-lucide:cable rtl-flip min-w-3 w-3 h-3 mx-1" aria-hidden="true" />
272+
</TooltipApp>
273+
</template>
274+
<CopyToClipboardButton
275+
v-if="resolvedVersion"
276+
:copied="copiedVersion"
277+
:copy-text="$t('package.copy_version')"
278+
@click="copyVersion()"
279+
class="inline"
280+
>
281+
<LinkBase
282+
v-if="requestedVersion && resolvedVersion !== requestedVersion"
283+
:to="packageRoute(packageName, resolvedVersion)"
284+
:title="$t('package.view_permalink')"
285+
dir="ltr"
286+
class="inline!"
287+
>{{ resolvedVersion }}</LinkBase
288+
>
289+
<span dir="ltr" v-else>v{{ resolvedVersion }}</span>
290+
</CopyToClipboardButton>
291+
<span
292+
v-if="requestedVersion && latestVersion && resolvedVersion !== latestVersion.version"
293+
class="text-fg-subtle text-sm text-nowrap ms-1"
294+
>{{ $t('package.not_latest') }}</span
295+
>
296+
</div>
297+
</div>
298+
<!-- Docs + Code — inline on desktop, floating bottom bar on mobile -->
299+
<nav
300+
v-if="resolvedVersion"
301+
:aria-label="$t('package.navigation')"
302+
class="flex gap-4 me-auto -mb-px"
303+
:style="navExtraOffsetStyle"
304+
:class="$style.packageNav"
305+
>
306+
<LinkBase
307+
v-if="docsLink"
308+
:to="docsLink"
309+
aria-keyshortcuts="d"
310+
class="decoration-none border-b-2 p-1 hover:border-accent/50"
311+
:class="page === 'docs' ? 'border-accent text-accent!' : 'border-transparent'"
312+
>
313+
{{ $t('package.links.docs') }}
314+
</LinkBase>
315+
<LinkBase
316+
v-if="codeLink"
317+
:to="codeLink"
318+
aria-keyshortcuts="."
319+
class="decoration-none border-b-2 p-1 hover:border-accent/50"
320+
:class="page === 'code' ? 'border-accent text-accent!' : 'border-transparent'"
321+
>
322+
{{ $t('package.links.code') }}
323+
</LinkBase>
324+
<LinkBase
325+
v-if="displayVersion && latestVersion && displayVersion.version !== latestVersion.version"
326+
:to="diffRoute(packageName, displayVersion.version, latestVersion.version)"
327+
:title="$t('compare.compare_versions_title')"
328+
class="decoration-none border-b-2 p-1 hover:border-accent/50"
329+
:class="page === 'diff' ? 'border-accent text-accent!' : 'border-transparent'"
330+
>
331+
{{ $t('compare.compare_versions') }}
332+
</LinkBase>
333+
</nav>
334+
</div>
333335
</template>
334336

335337
<style module>

app/components/Package/Sidebar.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ const offset = computed(() => {
2323
? content.value.offsetTop
2424
: container.value.offsetHeight - content.value.offsetTop - content.value.offsetHeight
2525
})
26+
const packageHeaderHeight = usePackageHeaderHeight()
27+
const stickyStyle = computed(() =>
28+
direction.value === 'up' ? { top: `${60 + packageHeaderHeight.value}px` } : { bottom: `32px` },
29+
)
2630
2731
const style = computed(() => {
2832
return direction.value === 'down'
@@ -42,6 +46,7 @@ const style = computed(() => {
4246
<div
4347
ref="content"
4448
class="sticky w-full group-data-[direction=up]:(self-start top-30 xl:top-14) group-data-[direction=down]:(self-end bottom-8)"
49+
:style="stickyStyle"
4550
>
4651
<slot />
4752
</div>

0 commit comments

Comments
 (0)