Skip to content

Commit d068685

Browse files
committed
refactor: configure more shortcuts and move logic to package-header
1 parent 64c37b6 commit d068685

5 files changed

Lines changed: 129 additions & 78 deletions

File tree

app/components/AppFooter.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ const closeModal = () => modalRef.value?.close?.()
9191
<kbd class="kbd">.</kbd>
9292
<span>{{ $t('shortcuts.open_code_view') }}</span>
9393
</li>
94+
<li class="flex gap-2 items-center">
95+
<kbd class="kbd">r</kbd>
96+
<span>{{ $t('shortcuts.open_readme') }}</span>
97+
</li>
9498
<li class="flex gap-2 items-center">
9599
<kbd class="kbd">d</kbd>
96100
<span>{{ $t('shortcuts.open_docs') }}</span>
@@ -99,6 +103,10 @@ const closeModal = () => modalRef.value?.close?.()
99103
<kbd class="kbd">c</kbd>
100104
<span>{{ $t('shortcuts.compare_from_package') }}</span>
101105
</li>
106+
<li class="flex gap-2 items-center">
107+
<kbd class="kbd">f</kbd>
108+
<span>{{ $t('shortcuts.open_diff') }}</span>
109+
</li>
102110
</ul>
103111
<p class="text-fg-muted leading-relaxed">
104112
<i18n-t keypath="shortcuts.disable_shortcuts" tag="span" scope="global">

app/components/Package/Header.vue

Lines changed: 112 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SCROLL_TO_TOP_THRESHOLD } from '~/composables/useScrollToTop'
55
import { useModal } from '~/composables/useModal'
66
import { useAtproto } from '~/composables/atproto/useAtproto'
77
import { togglePackageLike } from '~/utils/atproto/likes'
8+
import { isEditableElement } from '~/utils/input'
89
910
const props = defineProps<{
1011
pkg: Pick<SlimPackument, 'name' | 'versions' | 'dist-tags'> | null
@@ -13,10 +14,7 @@ const props = defineProps<{
1314
latestVersion: SlimVersion | null
1415
provenanceData: ProvenanceDetails | null
1516
provenanceStatus: string
16-
docsLink: RouteLocationRaw | null
17-
codeLink: RouteLocationRaw | null
1817
page: 'readme' | 'docs' | 'code' | 'diff'
19-
versionUrlPattern: string
2018
}>()
2119
2220
const { requestedVersion, orgName } = usePackageRoute()
@@ -80,6 +78,113 @@ function hasProvenance(version: PackumentVersion | null): boolean {
8078
return !!(version.dist as { attestations?: unknown }).attestations
8179
}
8280
81+
const router = useRouter()
82+
// Docs URL: use our generated API docs
83+
const docsLink = computed(() => {
84+
if (!props.resolvedVersion) return null
85+
86+
return {
87+
name: 'docs' as const,
88+
params: {
89+
path: [props.pkg?.name ?? '', 'v', props.resolvedVersion] satisfies [string, string, string],
90+
},
91+
}
92+
})
93+
94+
const codeLink = computed((): RouteLocationRaw | null => {
95+
if (props.pkg == null || props.resolvedVersion == null) {
96+
return null
97+
}
98+
const split = props.pkg.name.split('/')
99+
return {
100+
name: 'code',
101+
params: {
102+
org: split.length === 2 ? split[0] : undefined,
103+
packageName: split.length === 2 ? split[1]! : split[0]!,
104+
version: props.resolvedVersion,
105+
filePath: '',
106+
},
107+
}
108+
})
109+
110+
const readmeLink = computed((): RouteLocationRaw | null => {
111+
if (props.pkg == null || props.resolvedVersion == null) {
112+
return null
113+
}
114+
return packageRoute(props.pkg.name, props.resolvedVersion)
115+
})
116+
117+
const diffLink = computed((): RouteLocationRaw | null => {
118+
if (
119+
props.pkg == null ||
120+
props.resolvedVersion == null ||
121+
props.latestVersion == null ||
122+
props.latestVersion.version === props.resolvedVersion
123+
) {
124+
return null
125+
}
126+
return diffRoute(props.pkg.name, props.resolvedVersion, props.latestVersion.version)
127+
})
128+
129+
// URL pattern for version selector - includes file path if present
130+
const versionUrlPattern = computed(
131+
() => `/package/${props.pkg?.name || packageName.value}/v/{version}`,
132+
)
133+
134+
const keyboardShortcuts = useKeyboardShortcuts()
135+
136+
onKeyStroke(
137+
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, '.') && !isEditableElement(e.target),
138+
e => {
139+
if (codeLink.value === null) return
140+
e.preventDefault()
141+
142+
navigateTo(codeLink.value)
143+
},
144+
{ dedupe: true },
145+
)
146+
147+
onKeyStroke(
148+
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'r') && !isEditableElement(e.target),
149+
e => {
150+
if (readmeLink.value === null) return
151+
e.preventDefault()
152+
153+
navigateTo(readmeLink.value)
154+
},
155+
{ dedupe: true },
156+
)
157+
158+
onKeyStroke(
159+
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'd') && !isEditableElement(e.target),
160+
e => {
161+
if (!docsLink.value) return
162+
e.preventDefault()
163+
navigateTo(docsLink.value)
164+
},
165+
{ dedupe: true },
166+
)
167+
168+
onKeyStroke(
169+
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'c') && !isEditableElement(e.target),
170+
e => {
171+
if (!props.pkg) return
172+
e.preventDefault()
173+
router.push({ name: 'compare', query: { packages: props.pkg.name } })
174+
},
175+
{ dedupe: true },
176+
)
177+
178+
onKeyStroke(
179+
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'f') && !isEditableElement(e.target),
180+
e => {
181+
if (diffLink.value === null) return
182+
e.preventDefault()
183+
navigateTo(diffLink.value)
184+
},
185+
{ dedupe: true },
186+
)
187+
83188
//atproto
84189
// TODO: Maybe set this where it's not loaded here every load?
85190
const { user } = useAtproto()
@@ -288,8 +393,8 @@ const likeAction = async () => {
288393
:class="$style.packageNav"
289394
>
290395
<LinkBase
291-
v-if="docsLink"
292-
:to="docsLink"
396+
v-if="readmeLink"
397+
:to="readmeLink"
293398
aria-keyshortcuts="r"
294399
class="decoration-none border-b-2 p-1 hover:border-accent/50 lowercase"
295400
:class="page === 'readme' ? 'border-accent text-accent!' : 'border-transparent'"
@@ -315,8 +420,8 @@ const likeAction = async () => {
315420
{{ $t('package.links.code') }}
316421
</LinkBase>
317422
<LinkBase
318-
v-if="displayVersion && latestVersion && displayVersion.version !== latestVersion.version"
319-
:to="diffRoute(packageName, displayVersion.version, latestVersion.version)"
423+
v-if="diffLink"
424+
:to="diffLink"
320425
:title="$t('compare.compare_versions_title')"
321426
aria-keyshortcuts="f"
322427
class="decoration-none border-b-2 p-1 hover:border-accent/50"

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

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ import type { IconClass } from '~/types'
1414
import { assertValidPackageName } from '#shared/utils/npm'
1515
import { joinURL } from 'ufo'
1616
import { areUrlsEquivalent } from '#shared/utils/url'
17-
import { isEditableElement } from '~/utils/input'
1817
import { getDependencyCount } from '~/utils/npm/dependency-count'
1918
import { detectPublishSecurityDowngradeForVersion } from '~/utils/publish-security'
2019
import { useInstallSizeDiff } from '~/composables/useInstallSizeDiff'
2120
import { useViewOnGitProvider } from '~/composables/useViewOnGitProvider'
22-
import type { RouteLocationRaw } from 'vue-router'
2321
2422
defineOgImageComponent('Package', {
2523
name: () => packageName.value,
@@ -449,18 +447,6 @@ const homepageUrl = computed(() => {
449447
return homepage
450448
})
451449
452-
// Docs URL: use our generated API docs
453-
const docsLink = computed(() => {
454-
if (!resolvedVersion.value) return null
455-
456-
return {
457-
name: 'docs' as const,
458-
params: {
459-
path: [pkg.value!.name, 'v', resolvedVersion.value] satisfies [string, string, string],
460-
},
461-
}
462-
})
463-
464450
const fundingUrl = computed(() => {
465451
let funding = displayVersion.value?.funding
466452
if (Array.isArray(funding)) funding = funding[0]
@@ -552,59 +538,6 @@ useSeoMeta({
552538
twitterDescription: () => pkg.value?.description ?? '',
553539
})
554540
555-
const codeLink = computed((): RouteLocationRaw | null => {
556-
if (pkg.value == null || resolvedVersion.value == null) {
557-
return null
558-
}
559-
const split = pkg.value.name.split('/')
560-
return {
561-
name: 'code',
562-
params: {
563-
org: split.length === 2 ? split[0] : undefined,
564-
packageName: split.length === 2 ? split[1]! : split[0]!,
565-
version: resolvedVersion.value,
566-
filePath: '',
567-
},
568-
}
569-
})
570-
571-
const keyboardShortcuts = useKeyboardShortcuts()
572-
573-
onKeyStroke(
574-
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, '.') && !isEditableElement(e.target),
575-
e => {
576-
if (codeLink.value === null) return
577-
e.preventDefault()
578-
579-
navigateTo(codeLink.value)
580-
},
581-
{ dedupe: true },
582-
)
583-
584-
onKeyStroke(
585-
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'd') && !isEditableElement(e.target),
586-
e => {
587-
if (!docsLink.value) return
588-
e.preventDefault()
589-
navigateTo(docsLink.value)
590-
},
591-
{ dedupe: true },
592-
)
593-
594-
onKeyStroke(
595-
e => keyboardShortcuts.value && isKeyWithoutModifiers(e, 'c') && !isEditableElement(e.target),
596-
e => {
597-
if (!pkg.value) return
598-
e.preventDefault()
599-
router.push({ name: 'compare', query: { packages: pkg.value.name } })
600-
},
601-
)
602-
603-
// URL pattern for version selector - includes file path if present
604-
const versionUrlPattern = computed(
605-
() => `/package/${pkg.value?.name || packageName.value}/v/{version}`,
606-
)
607-
608541
const showSkeleton = shallowRef(false)
609542
</script>
610543

@@ -652,10 +585,7 @@ const showSkeleton = shallowRef(false)
652585
:latest-version="latestVersion"
653586
:provenance-data="provenanceData"
654587
:provenance-status="provenanceStatus"
655-
:docs-link="docsLink"
656-
:code-link="codeLink"
657588
:class="$style.areaHeader"
658-
:version-url-pattern="versionUrlPattern"
659589
page="readme"
660590
/>
661591
<article id="package-article" :class="$style.packagePage">

i18n/locales/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
"go_to_result": "Go to result",
3737
"open_code_view": "Open code view",
3838
"open_docs": "Open docs",
39-
"disable_shortcuts": "You can disable keyboard shortcuts in {settings}."
39+
"disable_shortcuts": "You can disable keyboard shortcuts in {settings}.",
40+
"open_readme": "Open readme",
41+
"open_diff": "Open version differences"
4042
},
4143
"search": {
4244
"label": "Search npm packages",

i18n/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@
114114
},
115115
"disable_shortcuts": {
116116
"type": "string"
117+
},
118+
"open_readme": {
119+
"type": "string"
120+
},
121+
"open_diff": {
122+
"type": "string"
117123
}
118124
},
119125
"additionalProperties": false

0 commit comments

Comments
 (0)