@@ -162,142 +162,125 @@ useSeoMeta({
162162
163163<template >
164164 <main class =" container flex-1 py-12 sm:py-16 w-full" >
165- <div class =" max-w-2xl mx-auto" >
166- <header class =" mb-12" >
167- <div class =" flex items-baseline justify-between gap-4 mb-4" >
168- <h1 class =" font-mono text-3xl sm:text-4xl font-medium" >
169- {{ $t('compare.packages.title') }}
170- </h1 >
171- <button
172- type =" button"
173- class =" cursor-pointer inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0"
174- @click =" router.back()"
175- v-if =" canGoBack"
176- >
177- <span class =" i-lucide:arrow-left rtl-flip w-4 h-4" aria-hidden =" true" />
178- <span class =" hidden sm:inline" >{{ $t('nav.back') }}</span >
179- </button >
180- </div >
181- <p class =" text-fg-muted text-lg" >
182- {{ $t('compare.packages.tagline') }}
183- </p >
184- </header >
185-
186- <!-- Package selector -->
187- <section class =" mb-8" aria-labelledby =" packages-heading" >
188- <h2 id =" packages-heading" class =" text-xs text-fg-subtle uppercase tracking-wider mb-3" >
189- {{ $t('compare.packages.section_packages') }}
165+ <header class =" mb-12" >
166+ <div class =" flex items-baseline justify-between gap-4 mb-4" >
167+ <h1 class =" font-mono text-3xl sm:text-4xl font-medium" >
168+ {{ $t('compare.packages.title') }}
169+ </h1 >
170+ <button
171+ type =" button"
172+ class =" cursor-pointer inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0"
173+ @click =" router.back()"
174+ v-if =" canGoBack"
175+ >
176+ <span class =" i-lucide:arrow-left rtl-flip w-4 h-4" aria-hidden =" true" />
177+ <span class =" hidden sm:inline" >{{ $t('nav.back') }}</span >
178+ </button >
179+ </div >
180+ <p class =" text-fg-muted text-lg" >
181+ {{ $t('compare.packages.tagline') }}
182+ </p >
183+ </header >
184+
185+ <!-- Package selector -->
186+ <section class =" mb-8" aria-labelledby =" packages-heading" >
187+ <h2 id =" packages-heading" class =" text-xs text-fg-subtle uppercase tracking-wider mb-3" >
188+ {{ $t('compare.packages.section_packages') }}
189+ </h2 >
190+ <ComparePackageSelector v-model =" packages" :max =" 4" />
191+
192+ <!-- "No dep" replacement suggestions (native, simple) -->
193+ <div v-if =" noDepSuggestions.length > 0" class =" mt-3 space-y-2" >
194+ <CompareReplacementSuggestion
195+ v-for =" suggestion in noDepSuggestions"
196+ :key =" suggestion.forPackage"
197+ :package-name =" suggestion.forPackage"
198+ :replacement =" suggestion.replacement"
199+ variant =" nodep"
200+ :show-action =" canAddNoDep"
201+ @add-no-dep =" addNoDep"
202+ />
203+ </div >
204+
205+ <!-- Informational replacement suggestions (documented) -->
206+ <div v-if =" infoSuggestions.length > 0" class =" mt-3 space-y-2" >
207+ <CompareReplacementSuggestion
208+ v-for =" suggestion in infoSuggestions"
209+ :key =" suggestion.forPackage"
210+ :package-name =" suggestion.forPackage"
211+ :replacement =" suggestion.replacement"
212+ variant =" info"
213+ />
214+ </div >
215+ </section >
216+
217+ <!-- Facet selector -->
218+ <section class =" mb-8" aria-labelledby =" facets-heading" >
219+ <div class =" flex items-center gap-2 mb-3" >
220+ <h2 id =" facets-heading" class =" text-xs text-fg-subtle uppercase tracking-wider" >
221+ {{ $t('compare.packages.section_facets') }}
190222 </h2 >
191- <ComparePackageSelector v-model =" packages" :max =" 4" />
192-
193- <!-- "No dep" replacement suggestions (native, simple) -->
194- <div v-if =" noDepSuggestions.length > 0" class =" mt-3 space-y-2" >
195- <CompareReplacementSuggestion
196- v-for =" suggestion in noDepSuggestions"
197- :key =" suggestion.forPackage"
198- :package-name =" suggestion.forPackage"
199- :replacement =" suggestion.replacement"
200- variant =" nodep"
201- :show-action =" canAddNoDep"
202- @add-no-dep =" addNoDep"
203- />
204- </div >
205-
206- <!-- Informational replacement suggestions (documented) -->
207- <div v-if =" infoSuggestions.length > 0" class =" mt-3 space-y-2" >
208- <CompareReplacementSuggestion
209- v-for =" suggestion in infoSuggestions"
210- :key =" suggestion.forPackage"
211- :package-name =" suggestion.forPackage"
212- :replacement =" suggestion.replacement"
213- variant =" info"
214- />
215- </div >
216- </section >
217-
218- <!-- Facet selector -->
219- <section class =" mb-8" aria-labelledby =" facets-heading" >
220- <div class =" flex items-center gap-2 mb-3" >
221- <h2 id =" facets-heading" class =" text-xs text-fg-subtle uppercase tracking-wider" >
222- {{ $t('compare.packages.section_facets') }}
223- </h2 >
224- <ButtonBase
225- size =" small"
226- :aria-pressed =" isAllSelected"
227- :disabled =" isAllSelected"
228- :aria-label =" $t('compare.facets.select_all')"
229- @click =" selectAll"
230- >
231- {{ $t('compare.facets.all') }}
232- </ButtonBase >
233- <span class =" text-3xs text-fg-muted/40" aria-hidden =" true" >/</span >
234- <ButtonBase
235- size =" small"
236- :aria-pressed =" isNoneSelected"
237- :disabled =" isNoneSelected"
238- :aria-label =" $t('compare.facets.deselect_all')"
239- @click =" deselectAll"
240- >
241- {{ $t('compare.facets.none') }}
242- </ButtonBase >
243- </div >
244- <CompareFacetSelector />
245- </section >
246-
247- <!-- Comparison grid -->
248- <section v-if =" canCompare" class =" mt-10" aria-labelledby =" comparison-heading" >
249- <CopyToClipboardButton
250- v-if =" packagesData && packagesData.some(p => p !== null)"
251- :copied =" copied"
252- :copy-text =" $t('compare.packages.copy_as_markdown')"
253- class =" mb-4"
254- :button-attrs =" { class: 'hidden md:inline-flex' }"
255- @click =" exportComparisonDataAsMarkdown"
223+ <ButtonBase
224+ size =" small"
225+ :aria-pressed =" isAllSelected"
226+ :disabled =" isAllSelected"
227+ :aria-label =" $t('compare.facets.select_all')"
228+ @click =" selectAll"
256229 >
257- < h2 id = " comparison-heading " class = " text-xs text-fg-subtle uppercase tracking-wider " >
258- {{ $t('compare.packages.section_comparison') }}
259- </ h2 >
260- </ CopyToClipboardButton >
261-
262- < h2
263- v-else
264- id = " comparison-heading "
265- class = " text-xs text-fg-subtle uppercase tracking-wider mb-4 "
230+ {{ $t('compare.facets.all') }}
231+ </ ButtonBase >
232+ < span class = " text-3xs text-fg-muted/40 " aria-hidden = " true " >/</ span >
233+ <ButtonBase
234+ size = " small "
235+ :aria-pressed = " isNoneSelected "
236+ :disabled = " isNoneSelected "
237+ :aria-label = " $t('compare.facets.deselect_all') "
238+ @click = " deselectAll "
266239 >
240+ {{ $t('compare.facets.none') }}
241+ </ButtonBase >
242+ </div >
243+ <CompareFacetSelector />
244+ </section >
245+
246+ <!-- Comparison grid -->
247+ <section v-if =" canCompare" class =" mt-10" aria-labelledby =" comparison-heading" >
248+ <CopyToClipboardButton
249+ v-if =" packagesData && packagesData.some(p => p !== null)"
250+ :copied =" copied"
251+ :copy-text =" $t('compare.packages.copy_as_markdown')"
252+ class =" mb-4"
253+ :button-attrs =" { class: 'hidden md:inline-flex' }"
254+ @click =" exportComparisonDataAsMarkdown"
255+ >
256+ <h2 id =" comparison-heading" class =" text-xs text-fg-subtle uppercase tracking-wider" >
267257 {{ $t('compare.packages.section_comparison') }}
268258 </h2 >
259+ </CopyToClipboardButton >
269260
270- <div
271- v-if ="
272- (status === 'pending' || status === 'idle') &&
273- (!packagesData || packagesData.every(p => p === null))
274- "
275- class =" flex items-center justify-center py-12"
276- >
277- <LoadingSpinner :text =" $t('compare.packages.loading')" />
278- </div >
279-
280- <div v-else-if =" packagesData && packagesData.some(p => p !== null)" >
281- <!-- Desktop: Grid layout -->
282- <div class =" hidden md:block overflow-x-auto" >
283- <CompareComparisonGrid :columns =" gridColumns" :show-no-dependency =" showNoDependency" >
284- <CompareFacetRow
285- v-for =" facet in selectedFacets"
286- :key =" facet.id"
287- :label =" facet.label"
288- :description =" facet.description"
289- :values =" getFacetValues(facet.id)"
290- :facet-loading =" isFacetLoading(facet.id)"
291- :column-loading =" columnLoading"
292- :bar =" facet.id !== 'lastUpdated'"
293- :headers =" gridHeaders"
294- />
295- </CompareComparisonGrid >
296- </div >
297-
298- <!-- Mobile: Card-based layout -->
299- <div class =" md:hidden space-y-3" >
300- <CompareFacetCard
261+ <h2
262+ v-else
263+ id =" comparison-heading"
264+ class =" text-xs text-fg-subtle uppercase tracking-wider mb-4"
265+ >
266+ {{ $t('compare.packages.section_comparison') }}
267+ </h2 >
268+
269+ <div
270+ v-if ="
271+ (status === 'pending' || status === 'idle') &&
272+ (!packagesData || packagesData.every(p => p === null))
273+ "
274+ class =" flex items-center justify-center py-12"
275+ >
276+ <LoadingSpinner :text =" $t('compare.packages.loading')" />
277+ </div >
278+
279+ <div v-else-if =" packagesData && packagesData.some(p => p !== null)" >
280+ <!-- Desktop: Grid layout -->
281+ <div class =" hidden md:block overflow-x-auto" >
282+ <CompareComparisonGrid :columns =" gridColumns" :show-no-dependency =" showNoDependency" >
283+ <CompareFacetRow
301284 v-for =" facet in selectedFacets"
302285 :key =" facet.id"
303286 :label =" facet.label"
@@ -308,42 +291,54 @@ useSeoMeta({
308291 :bar =" facet.id !== 'lastUpdated'"
309292 :headers =" gridHeaders"
310293 />
311- </div >
312-
313- <h2
314- id =" trends-comparison-heading"
315- class =" text-xs text-fg-subtle uppercase tracking-wider mb-4 mt-10"
316- >
317- {{ $t('compare.facets.trends.title') }}
318- </h2 >
319-
320- <CompareLineChart :packages =" packages.filter(p => p !== NO_DEPENDENCY_ID)" />
294+ </CompareComparisonGrid >
321295 </div >
322296
323- <div v-else-if =" status === 'error'" class =" text-center py-12" role =" alert" >
324- <p class =" text-fg-muted" >{{ $t('compare.packages.error') }}</p >
325- </div >
326- <div v-else class =" flex items-center justify-center py-12" >
327- <LoadingSpinner :text =" $t('compare.packages.loading')" />
297+ <!-- Mobile: Card-based layout -->
298+ <div class =" md:hidden space-y-3" >
299+ <CompareFacetCard
300+ v-for =" facet in selectedFacets"
301+ :key =" facet.id"
302+ :label =" facet.label"
303+ :description =" facet.description"
304+ :values =" getFacetValues(facet.id)"
305+ :facet-loading =" isFacetLoading(facet.id)"
306+ :column-loading =" columnLoading"
307+ :bar =" facet.id !== 'lastUpdated'"
308+ :headers =" gridHeaders"
309+ />
328310 </div >
329- </section >
330311
331- <!-- Empty state -->
332- <section
333- v-else
334- class =" text-center px-1.5 py-16 border border-dashed border-border-hover rounded-lg"
335- >
336- <div
337- class =" i-lucide:git-compare w-12 h-12 text-fg-subtle mx-auto mb-4"
338- aria-hidden =" true"
339- />
340- <h2 class =" font-mono text-lg text-fg-muted mb-2" >
341- {{ $t('compare.packages.empty_title') }}
312+ <h2
313+ id =" trends-comparison-heading"
314+ class =" text-xs text-fg-subtle uppercase tracking-wider mb-4 mt-10"
315+ >
316+ {{ $t('compare.facets.trends.title') }}
342317 </h2 >
343- <p class =" text-sm text-fg-subtle max-w-md mx-auto" >
344- {{ $t('compare.packages.empty_description') }}
345- </p >
346- </section >
347- </div >
318+
319+ <CompareLineChart :packages =" packages.filter(p => p !== NO_DEPENDENCY_ID)" />
320+ </div >
321+
322+ <div v-else-if =" status === 'error'" class =" text-center py-12" role =" alert" >
323+ <p class =" text-fg-muted" >{{ $t('compare.packages.error') }}</p >
324+ </div >
325+ <div v-else class =" flex items-center justify-center py-12" >
326+ <LoadingSpinner :text =" $t('compare.packages.loading')" />
327+ </div >
328+ </section >
329+
330+ <!-- Empty state -->
331+ <section
332+ v-else
333+ class =" text-center px-1.5 py-16 border border-dashed border-border-hover rounded-lg"
334+ >
335+ <div class =" i-lucide:git-compare w-12 h-12 text-fg-subtle mx-auto mb-4" aria-hidden =" true" />
336+ <h2 class =" font-mono text-lg text-fg-muted mb-2" >
337+ {{ $t('compare.packages.empty_title') }}
338+ </h2 >
339+ <p class =" text-sm text-fg-subtle max-w-md mx-auto" >
340+ {{ $t('compare.packages.empty_description') }}
341+ </p >
342+ </section >
348343 </main >
349344</template >
0 commit comments