Skip to content
Open
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
41 changes: 41 additions & 0 deletions app/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,44 @@ html:has(dialog:modal) {
overflow: hidden;
scrollbar-gutter: stable;
}

/* No-JS Alert Styles */
.noscript-alert {
position: absolute;
top: 58px;
left: 0;
width: 100%;

padding: 0.5rem 1rem;

/* Square and no side borders */
border-radius: 0;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #f87171;

font-size: 0.875rem;
line-height: 1.25rem;
text-align: center;
z-index: 40;

/* Default (Dark) */
background-color: rgba(127, 29, 29, 0.2); /* red-900/20 */
color: #fecaca; /* red-200 */
}

@media (min-width: 768px) {
.noscript-alert {
padding: 0.75rem 1rem;
font-size: 1rem;
line-height: 1.5rem;
}
}

/* Light theme override */
:root[data-theme='light'] .noscript-alert {
border-color: #b91c1c; /* red-700 */
background-color: #fef2f2; /* red-50 */
color: #991b1b; /* red-800 */
}
4 changes: 2 additions & 2 deletions app/components/Compare/FacetRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ function isCellLoading(index: number): boolean {
/>
</template>

<!-- No data -->
<!-- No data (Skeleton) -->
<template v-else-if="!value">
<span class="text-fg-subtle text-sm">-</span>
<SkeletonInline class="w-16 h-4" />
</template>

<!-- Value display -->
Expand Down
23 changes: 17 additions & 6 deletions app/composables/usePackageComparison.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,18 @@ export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {
const compactNumberFormatter = useCompactNumberFormatter()
const bytesFormatter = useBytesFormatter()
const packages = computed(() => toValue(packageNames))
const nuxt = useNuxtApp()

// Cache of fetched data by package name (source of truth)
const cache = shallowRef(new Map<string, PackageComparisonData>())

// Derived array in current package order
const packagesData = computed(() => packages.value.map(name => cache.value.get(name) ?? null))
const packagesData = computed<false | (PackageComparisonData | null)[]>(
() =>
import.meta.client &&
!nuxt.isHydrating &&
packages.value.map(name => cache.value.get(name) ?? null),
)

const status = shallowRef<'idle' | 'pending' | 'success' | 'error'>('idle')
const error = shallowRef<Error | null>(null)
Expand Down Expand Up @@ -250,17 +256,22 @@ export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {
// Watch for package changes and refetch (client-side only)
if (import.meta.client) {
watch(
packages,
newPackages => {
fetchPackages(newPackages)
() => [nuxt.isHydrating, packages.value] as const,
([isHydrating, newPackages]) => {
if (!isHydrating) {
fetchPackages(newPackages)
}
},
{ immediate: true },
)
}

// Compute values for each facet
function getFacetValues(facet: ComparisonFacet): (FacetValue | null)[] {
if (!packagesData.value || packagesData.value.length === 0) return []
// If not ready or no data, return array of nulls to render skeletons
if (nuxt.isHydrating || !packagesData.value || packagesData.value.length === 0) {
return Array.from({ length: packages.value.length }, () => null)
}

return packagesData.value.map(pkg => {
if (!pkg) return null
Expand All @@ -277,7 +288,7 @@ export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {

// Check if a facet depends on slow-loading data
function isFacetLoading(facet: ComparisonFacet): boolean {
if (!installSizeLoading.value) return false
if (nuxt.isHydrating || !installSizeLoading.value) return false
// These facets depend on install-size API
return facet === 'installSize' || facet === 'totalDependencies'
}
Expand Down
Loading
Loading