Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 90 additions & 33 deletions app/pages/[...package].vue
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,15 @@ defineOgImageComponent('Package', {
</script>

<template>
<main class="container py-8 sm:py-12 overflow-hidden w-full">
<main class="container py-8 xl:py-12">
<PackageSkeleton v-if="status === 'pending'" />

<article v-else-if="status === 'success' && pkg" class="motion-safe:animate-fade-in min-w-0">
<article
v-else-if="status === 'success' && pkg"
class="package-page motion-safe:animate-fade-in"
>
<!-- Package header -->
<header class="mb-8 pb-8 border-b border-border">
<header class="area-header pb-8 border-b border-border">
<div class="mb-4">
<!-- Package name and version -->
<div class="flex items-baseline gap-2 mb-1.5 sm:gap-3 sm:mb-2 flex-wrap min-w-0">
Expand Down Expand Up @@ -660,10 +663,11 @@ defineOgImageComponent('Package', {
v-if="displayVersion"
:package-name="pkg.name"
:version="displayVersion.version"
class="area-vulns"
/>

<!-- Install command with package manager selector -->
<section aria-labelledby="install-heading" class="mb-8">
<section aria-labelledby="install-heading" class="area-install">
<div class="flex flex-wrap items-center justify-between mb-3">
<h2 id="install-heading" class="text-xs text-fg-subtle uppercase tracking-wider">
{{ $t('package.install.title') }}
Expand Down Expand Up @@ -764,35 +768,28 @@ defineOgImageComponent('Package', {
</div>
</section>

<!-- Two column layout for sidebar content -->
<div class="grid lg:grid-cols-3 gap-8">
<!-- Main content (README) -->
<div class="lg:col-span-2 order-2 lg:order-1 min-w-0">
<section aria-labelledby="readme-heading">
<h2 id="readme-heading" class="text-xs text-fg-subtle uppercase tracking-wider mb-4">
{{ $t('package.readme.title') }}
</h2>
<!-- eslint-disable vue/no-v-html -- HTML is sanitized server-side -->
<div
v-if="readmeData?.html"
class="readme-content prose prose-invert max-w-none"
v-html="readmeData.html"
/>
<p v-else class="text-fg-subtle italic">
{{ $t('package.readme.no_readme') }}
<a
v-if="repositoryUrl"
:href="repositoryUrl"
rel="noopener noreferrer"
class="link"
>{{ $t('package.readme.view_on_github') }}</a
>
</p>
</section>
</div>
<!-- README -->
<section aria-labelledby="readme-heading" class="area-readme min-w-0">
<h2 id="readme-heading" class="text-xs text-fg-subtle uppercase tracking-wider mb-4">
{{ $t('package.readme.title') }}
</h2>
<!-- eslint-disable vue/no-v-html -- HTML is sanitized server-side -->
<div
v-if="readmeData?.html"
class="readme-content prose prose-invert max-w-[70ch]"
v-html="readmeData.html"
/>
<p v-else class="text-fg-subtle italic">
{{ $t('package.readme.no_readme') }}
<a v-if="repositoryUrl" :href="repositoryUrl" rel="noopener noreferrer" class="link">{{
$t('package.readme.view_on_github')
}}</a>
</p>
</section>

<div class="area-sidebar">
<!-- Sidebar -->
<div class="order-1 lg:order-2 space-y-6 sm:space-y-8 min-w-0 overflow-hidden">
<aside class="sticky top-20 space-y-6 sm:space-y-8 min-w-0 overflow-hidden">
<!-- Maintainers (with admin actions when connected) -->
<PackageMaintainers :package-name="pkg.name" :maintainers="pkg.maintainers" />

Expand Down Expand Up @@ -883,12 +880,16 @@ defineOgImageComponent('Package', {
:peer-dependencies-meta="displayVersion?.peerDependenciesMeta"
:optional-dependencies="displayVersion?.optionalDependencies"
/>
</div>
</aside>
</div>
</article>

<!-- Error state -->
<div v-else-if="status === 'error'" role="alert" class="py-20 text-center">
<div
v-else-if="status === 'error'"
role="alert"
class="flex flex-col items-center py-20 text-center"
>
<h1 class="font-mono text-2xl font-medium mb-4">{{ $t('package.not_found') }}</h1>
<p class="text-fg-muted mb-8">
{{ error?.message ?? $t('package.not_found_message') }}
Expand All @@ -897,3 +898,59 @@ defineOgImageComponent('Package', {
</div>
</main>
</template>

<style scoped>
.package-page {
display: grid;
gap: 2rem;

/* Mobile: single column, sidebar above readme */
grid-template-columns: 1fr;
grid-template-areas:
'header'
'install'
'vulns'
'sidebar'
'readme';
}

/* Tablet/medium: header/install/vulns full width, readme+sidebar side by side */
@media (min-width: 1024px) {
.package-page {
grid-template-columns: 2fr 1fr;
grid-template-areas:
'header header'
'install install'
'vulns vulns'
'readme sidebar';
}
}

/* Desktop: floating sidebar alongside all content */
@media (min-width: 1280px) {
.package-page {
grid-template-columns: 1fr 20rem;
grid-template-areas:
'header sidebar'
'install sidebar'
'vulns sidebar'
'readme sidebar';
}
}

.area-header {
grid-area: header;
}
.area-install {
grid-area: install;
}
.area-vulns {
grid-area: vulns;
}
.area-readme {
grid-area: readme;
}
.area-sidebar {
grid-area: sidebar;
}
</style>
4 changes: 2 additions & 2 deletions app/pages/search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ defineOgImageComponent('Default', {
<main class="overflow-x-hidden">
<!-- Sticky search header - positioned below AppHeader (h-14 = 56px) -->
<header class="sticky top-14 z-40 bg-bg/95 backdrop-blur-sm border-b border-border">
<div class="container py-4">
<div class="container-sm py-4">
<h1 class="font-mono text-xl sm:text-2xl font-medium mb-4">search</h1>

<search>
Expand Down Expand Up @@ -757,7 +757,7 @@ defineOgImageComponent('Default', {
</header>

<!-- Results area with container padding -->
<div class="container pt-20 pb-6">
<div class="container-sm pt-20 pb-6">
<section v-if="query" aria-label="Search results" @keydown="handleResultsKeydown">
<!-- Initial loading (only after user interaction, not during view transition) -->
<LoadingSpinner v-if="showSearching" :text="$t('search.searching')" />
Expand Down
3 changes: 2 additions & 1 deletion uno.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ export default defineConfig({
} satisfies Theme,
shortcuts: [
// Layout
['container', 'max-w-4xl mx-auto px-4 sm:px-6'],
['container', 'max-w-6xl mx-auto px-4 sm:px-6'],
['container-sm', 'max-w-4xl mx-auto px-4 sm:px-6'],

// Focus states - subtle but accessible
['focus-ring', 'outline-none focus-visible:(ring-2 ring-fg/10 ring-offset-2)'],
Expand Down