[READ-ONLY] a fast, modern browser for the npm registry
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: remove sticky footer and add `/about` page

+443 -135
+3 -1
README.md
··· 9 9 </p> 10 10 11 11 - [👉 &nbsp;Check it out](https://npmx.dev/) 12 + - [📖 &nbsp;About npmx](https://npmx.dev/about) 12 13 13 14 ## Vision 14 15 15 - The aim of [npmx.dev](https://npmx.dev) is to provide a better browser for the npm registry &ndash; fast, modern, and accessible. We don't aim to replace the [npmjs.com](https://www.npmjs.com/) registry, just provide a better UI and DX. 16 + The aim of [npmx.dev](https://npmx.dev) is to provide a better browser for the npm registry &ndash; fast, modern, and accessible. We don't aim to replace the [npmjs.com](https://www.npmjs.com/) registry, just provide a better UI, DX, and admin experience. 16 17 17 18 - **Speed first** &ndash; Layout shift, flakiness, slowness is The Worst. Fast searching, filtering, and navigation. 18 19 - **URL compatible** &ndash; Replace `npmjs.com` with `xnpmjs.com` or `npmx.dev` in any URL and it just works. 19 20 - **Simplicity** &ndash; No noise, cluttered display, or confusing UI. If in doubt: choose simplicity. 21 + - **Admin UI** &ndash; Manage your packages, teams, and organizations from the browser, powered by your local npm CLI. 20 22 21 23 ## Shortcuts 22 24
-1
app/assets/main.css
··· 76 76 background-color: var(--bg); 77 77 color: var(--fg); 78 78 line-height: 1.6; 79 - padding-bottom: var(--footer-height, 0); 80 79 } 81 80 82 81 /* Default link styling for accessibility on dark background */
+21 -130
app/components/AppFooter.vue
··· 1 - <script setup lang="ts"> 2 - const isMounted = shallowRef(false) 3 - const isVisible = shallowRef(false) 4 - const isScrollable = shallowRef(true) 5 - const lastScrollY = shallowRef(0) 6 - const footerRef = useTemplateRef('footerRef') 7 - 8 - // Check if CSS scroll-state container queries are supported 9 - // Once this becomes baseline, we can remove the JS scroll handling entirely 10 - const supportsScrollStateQueries = useSupported(() => { 11 - return isMounted.value && CSS.supports('container-type', 'scroll-state') 12 - }) 13 - 14 - function checkScrollable() { 15 - return document.documentElement.scrollHeight > window.innerHeight 16 - } 17 - 18 - function onScroll() { 19 - // Skip JS-based visibility logic if CSS scroll-state queries handle it 20 - if (supportsScrollStateQueries.value) return 21 - 22 - const currentY = window.scrollY 23 - const diff = lastScrollY.value - currentY 24 - const nearBottom = currentY + window.innerHeight >= document.documentElement.scrollHeight - 50 25 - 26 - // Scrolling UP or near bottom -> show 27 - if (Math.abs(diff) > 10) { 28 - isVisible.value = diff > 0 || nearBottom 29 - lastScrollY.value = currentY 30 - } 31 - 32 - // At top -> hide 33 - if (currentY < 100) { 34 - isVisible.value = false 35 - } 36 - 37 - // Near bottom -> always show 38 - if (nearBottom) { 39 - isVisible.value = true 40 - } 41 - } 42 - 43 - function updateFooterPadding() { 44 - const height = isScrollable.value && footerRef.value ? footerRef.value.offsetHeight : 0 45 - document.documentElement.style.setProperty('--footer-height', `${height}px`) 46 - } 47 - 48 - function onResize() { 49 - isScrollable.value = checkScrollable() 50 - updateFooterPadding() 51 - } 52 - 53 - useEventListener('scroll', onScroll, { passive: true }) 54 - useEventListener('resize', onResize, { passive: true }) 55 - 56 - onMounted(() => { 57 - nextTick(() => { 58 - lastScrollY.value = window.scrollY 59 - isScrollable.value = checkScrollable() 60 - updateFooterPadding() 61 - // Only apply dynamic classes after mount to avoid hydration mismatch 62 - isMounted.value = true 63 - }) 64 - }) 65 - </script> 66 - 67 1 <template> 68 - <footer 69 - ref="footerRef" 70 - aria-label="Site footer" 71 - class="border-t border-border bg-bg/90 backdrop-blur-md" 72 - :class="[ 73 - // When CSS scroll-state queries are supported, use CSS-only approach 74 - supportsScrollStateQueries 75 - ? 'footer-scroll-state' 76 - : // JS-controlled: fixed position, hidden by default, transition only after mount 77 - isScrollable 78 - ? [ 79 - 'fixed bottom-0 left-0 right-0 z-40', 80 - isMounted && 'transition-transform duration-300 ease-out', 81 - isVisible ? 'translate-y-0' : 'translate-y-full', 82 - ] 83 - : 'mt-auto', 84 - ]" 85 - > 86 - <div class="container py-2 sm:py-6 flex flex-col gap-1 sm:gap-3 text-fg-subtle text-sm"> 87 - <div class="flex flex-row items-center justify-between gap-2 sm:gap-4"> 2 + <footer class="border-t border-border mt-auto" aria-label="Site footer"> 3 + <div class="container py-3 sm:py-8 flex flex-col gap-2 sm:gap-4 text-fg-subtle text-sm"> 4 + <div class="flex flex-col sm:flex-row items-center justify-between gap-2 sm:gap-4"> 88 5 <p class="font-mono m-0 hidden sm:block">{{ $t('tagline') }}</p> 89 - <!-- On mobile, show disclaimer here instead of tagline --> 90 - <p class="text-xs text-fg-muted m-0 sm:hidden">{{ $t('non_affiliation_disclaimer') }}</p> 91 - <div class="flex items-center gap-4 sm:gap-6"> 6 + <div class="flex items-center gap-3 sm:gap-6"> 7 + <NuxtLink 8 + to="/about" 9 + class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center" 10 + > 11 + {{ $t('footer.about') }} 12 + </NuxtLink> 92 13 <a 93 14 href="https://docs.npmx.dev" 94 15 target="_blank" 95 16 rel="noopener noreferrer" 96 - class="link-subtle font-mono text-xs min-h-11 min-w- flex items-center" 17 + class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center gap-1" 97 18 > 98 19 {{ $t('footer.docs') }} 20 + <span class="i-carbon-launch w-3 h-3" aria-hidden="true" /> 99 21 </a> 100 22 <a 101 23 href="https://repo.npmx.dev" 102 24 target="_blank" 103 25 rel="noopener noreferrer" 104 - class="link-subtle font-mono text-xs min-h-11 min-w- flex items-center" 26 + class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center gap-1" 105 27 > 106 28 {{ $t('footer.source') }} 29 + <span class="i-carbon-launch w-3 h-3" aria-hidden="true" /> 107 30 </a> 108 31 <a 109 32 href="https://social.npmx.dev" 110 33 target="_blank" 111 34 rel="noopener noreferrer" 112 - class="link-subtle font-mono text-xs min-h-11 min-w-11 flex items-center" 35 + class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center gap-1" 113 36 > 114 37 {{ $t('footer.social') }} 38 + <span class="i-carbon-launch w-3 h-3" aria-hidden="true" /> 115 39 </a> 116 40 <a 117 41 href="https://chat.npmx.dev" 118 42 target="_blank" 119 43 rel="noopener noreferrer" 120 - class="link-subtle font-mono text-xs min-h-11 min-w-11 flex items-center" 44 + class="link-subtle font-mono text-xs min-h-8 sm:min-h-11 flex items-center gap-1" 121 45 > 122 46 {{ $t('footer.chat') }} 47 + <span class="i-carbon-launch w-3 h-3" aria-hidden="true" /> 123 48 </a> 124 49 </div> 125 50 </div> 126 - <p class="text-xs text-fg-muted text-center sm:text-left m-0 hidden sm:block"> 127 - {{ $t('trademark_disclaimer') }} 51 + <p class="text-xs text-fg-muted text-center sm:text-left m-0"> 52 + <span class="sm:hidden">{{ $t('non_affiliation_disclaimer') }}</span> 53 + <span class="hidden sm:inline">{{ $t('trademark_disclaimer') }}</span> 128 54 </p> 129 55 </div> 130 56 </footer> 131 57 </template> 132 - 133 - <style scoped> 134 - /* 135 - * CSS scroll-state container queries (Chrome 133+) 136 - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@container#scroll-state_container_descriptors 137 - * 138 - * This provides a pure CSS solution for showing/hiding the footer based on scroll state. 139 - * The JS fallback handles browsers without support. 140 - * Once scroll-state queries become baseline, we can remove the JS scroll handling entirely. 141 - */ 142 - @supports (container-type: scroll-state) { 143 - .footer-scroll-state { 144 - position: fixed; 145 - bottom: 0; 146 - left: 0; 147 - right: 0; 148 - z-index: 40; 149 - /* Hidden by default (translated off-screen) */ 150 - transform: translateY(100%); 151 - } 152 - 153 - @media (prefers-reduced-motion: no-preference) { 154 - .footer-scroll-state { 155 - transition: transform 0.3s ease-out; 156 - } 157 - } 158 - 159 - /* Show footer when user can scroll up (meaning they've scrolled down) */ 160 - @container scroll-state(scrollable: top) { 161 - .footer-scroll-state { 162 - transform: translateY(0); 163 - } 164 - } 165 - } 166 - </style>
+228
app/pages/about.vue
··· 1 + <script setup lang="ts"> 2 + useSeoMeta({ 3 + title: () => `${$t('about.title')} - npmx`, 4 + description: () => $t('about.meta_description'), 5 + }) 6 + 7 + defineOgImageComponent('Default', { 8 + title: () => $t('about.title'), 9 + description: () => $t('tagline'), 10 + }) 11 + 12 + const pmLinks = { 13 + npm: 'https://www.npmjs.com/', 14 + pnpm: 'https://pnpm.io/', 15 + yarn: 'https://yarnpkg.com/', 16 + bun: 'https://bun.sh/', 17 + deno: 'https://deno.com/', 18 + vlt: 'https://www.vlt.sh/', 19 + } 20 + </script> 21 + 22 + <template> 23 + <main class="container py-12 sm:py-16 min-h-screen"> 24 + <article class="max-w-2xl mx-auto"> 25 + <header class="mb-12"> 26 + <h1 class="font-mono text-3xl sm:text-4xl font-medium mb-4">{{ $t('about.heading') }}</h1> 27 + <p class="text-fg-muted text-lg"> 28 + {{ $t('tagline') }} 29 + </p> 30 + </header> 31 + 32 + <section class="prose prose-invert max-w-none space-y-8"> 33 + <div> 34 + <h2 class="text-xs text-fg-subtle uppercase tracking-wider mb-4"> 35 + {{ $t('about.what_we_are.title') }} 36 + </h2> 37 + <p class="text-fg-muted leading-relaxed mb-4"> 38 + <i18n-t keypath="about.what_we_are.description" tag="span"> 39 + <template #betterUxDx> 40 + <strong class="text-fg">{{ $t('about.what_we_are.better_ux_dx') }}</strong> 41 + </template> 42 + <template #jsr> 43 + <a 44 + href="https://jsr.io/" 45 + target="_blank" 46 + rel="noopener noreferrer" 47 + class="link text-fg" 48 + >JSR</a 49 + > 50 + </template> 51 + </i18n-t> 52 + </p> 53 + <p class="text-fg-muted leading-relaxed"> 54 + <i18n-t keypath="about.what_we_are.admin_description" tag="span"> 55 + <template #adminUi> 56 + <strong class="text-fg">{{ $t('about.what_we_are.admin_ui') }}</strong> 57 + </template> 58 + </i18n-t> 59 + </p> 60 + </div> 61 + 62 + <div> 63 + <h2 class="text-xs text-fg-subtle uppercase tracking-wider mb-4"> 64 + {{ $t('about.what_we_are_not.title') }} 65 + </h2> 66 + <ul class="space-y-3 text-fg-muted list-none p-0"> 67 + <li class="flex items-start gap-3"> 68 + <span class="text-fg-subtle shrink-0 mt-1">&mdash;</span> 69 + <span> 70 + <strong class="text-fg">{{ 71 + $t('about.what_we_are_not.not_package_manager') 72 + }}</strong> 73 + {{ ' ' }} 74 + <i18n-t keypath="about.what_we_are_not.package_managers_exist" tag="span"> 75 + <template #already>{{ $t('about.what_we_are_not.words.already') }}</template> 76 + <template #people> 77 + <a 78 + :href="pmLinks.npm" 79 + target="_blank" 80 + rel="noopener noreferrer" 81 + class="text-fg-muted hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg" 82 + >{{ $t('about.what_we_are_not.words.people') }}</a 83 + > 84 + </template> 85 + <template #building> 86 + <a 87 + :href="pmLinks.pnpm" 88 + target="_blank" 89 + rel="noopener noreferrer" 90 + class="text-fg-muted hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg" 91 + >{{ $t('about.what_we_are_not.words.building') }}</a 92 + > 93 + </template> 94 + <template #really> 95 + <a 96 + :href="pmLinks.yarn" 97 + target="_blank" 98 + rel="noopener noreferrer" 99 + class="text-fg-muted hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg" 100 + >{{ $t('about.what_we_are_not.words.really') }}</a 101 + > 102 + </template> 103 + <template #cool> 104 + <a 105 + :href="pmLinks.bun" 106 + target="_blank" 107 + rel="noopener noreferrer" 108 + class="text-fg-muted hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg" 109 + >{{ $t('about.what_we_are_not.words.cool') }}</a 110 + > 111 + </template> 112 + <template #package> 113 + <a 114 + :href="pmLinks.deno" 115 + target="_blank" 116 + rel="noopener noreferrer" 117 + class="text-fg-muted hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg" 118 + >{{ $t('about.what_we_are_not.words.package') }}</a 119 + > 120 + </template> 121 + <template #managers> 122 + <a 123 + :href="pmLinks.vlt" 124 + target="_blank" 125 + rel="noopener noreferrer" 126 + class="text-fg-muted hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg" 127 + >{{ $t('about.what_we_are_not.words.managers') }}</a 128 + > 129 + </template> 130 + </i18n-t> 131 + </span> 132 + </li> 133 + <li class="flex items-start gap-3"> 134 + <span class="text-fg-subtle shrink-0 mt-1">&mdash;</span> 135 + <span> 136 + <strong class="text-fg">{{ $t('about.what_we_are_not.not_registry') }}</strong> 137 + {{ $t('about.what_we_are_not.registry_description') }} 138 + </span> 139 + </li> 140 + </ul> 141 + </div> 142 + 143 + <div> 144 + <h2 class="text-xs text-fg-subtle uppercase tracking-wider mb-4"> 145 + {{ $t('about.vision.title') }} 146 + </h2> 147 + <ul class="space-y-3 text-fg-muted list-none p-0"> 148 + <li class="flex items-start gap-3"> 149 + <span class="text-accent shrink-0 mt-1.5 w-1.5 h-1.5 rounded-full bg-current" /> 150 + <span> 151 + <strong class="text-fg">{{ $t('about.vision.speed_first') }}</strong> &mdash; 152 + {{ $t('about.vision.speed_first_description') }} 153 + </span> 154 + </li> 155 + <li class="flex items-start gap-3"> 156 + <span class="text-accent shrink-0 mt-1.5 w-1.5 h-1.5 rounded-full bg-current" /> 157 + <span> 158 + <strong class="text-fg">{{ $t('about.vision.url_compatible') }}</strong> &mdash; 159 + <i18n-t keypath="about.vision.url_compatible_description" tag="span"> 160 + <template #npmjs> 161 + <code class="text-sm bg-bg-subtle px-1.5 py-0.5 rounded">npmjs.com</code> 162 + </template> 163 + <template #npmx> 164 + <code class="text-sm bg-bg-subtle px-1.5 py-0.5 rounded">npmx.dev</code> 165 + </template> 166 + </i18n-t> 167 + </span> 168 + </li> 169 + <li class="flex items-start gap-3"> 170 + <span class="text-accent shrink-0 mt-1.5 w-1.5 h-1.5 rounded-full bg-current" /> 171 + <span> 172 + <strong class="text-fg">{{ $t('about.vision.simplicity') }}</strong> &mdash; 173 + {{ $t('about.vision.simplicity_description') }} 174 + </span> 175 + </li> 176 + </ul> 177 + </div> 178 + 179 + <div> 180 + <h2 class="text-xs text-fg-subtle uppercase tracking-wider mb-4"> 181 + {{ $t('about.open_source.title') }} 182 + </h2> 183 + <p class="text-fg-muted leading-relaxed"> 184 + <i18n-t keypath="about.open_source.description" tag="span"> 185 + <template #github> 186 + <a 187 + href="https://repo.npmx.dev" 188 + target="_blank" 189 + rel="noopener noreferrer" 190 + class="link text-fg" 191 + >{{ $t('about.open_source.github') }}</a 192 + > 193 + </template> 194 + <template #discord> 195 + <a 196 + href="https://chat.npmx.dev" 197 + target="_blank" 198 + rel="noopener noreferrer" 199 + class="link text-fg" 200 + >{{ $t('about.open_source.discord') }}</a 201 + > 202 + </template> 203 + <template #bluesky> 204 + <a 205 + href="https://social.npmx.dev" 206 + target="_blank" 207 + rel="noopener noreferrer" 208 + class="link text-fg" 209 + >{{ $t('about.open_source.bluesky') }}</a 210 + > 211 + </template> 212 + </i18n-t> 213 + </p> 214 + </div> 215 + </section> 216 + 217 + <footer class="mt-16 pt-8 border-t border-border"> 218 + <NuxtLink 219 + to="/" 220 + class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-[color] duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 221 + > 222 + <span class="i-carbon-arrow-left w-4 h-4" aria-hidden="true" /> 223 + {{ $t('about.back_home') }} 224 + </NuxtLink> 225 + </footer> 226 + </article> 227 + </main> 228 + </template>
+4 -3
app/pages/index.vue
··· 68 68 :placeholder="$t('search.placeholder')" 69 69 v-bind="noCorrect" 70 70 autofocus 71 - class="w-full bg-bg-subtle border border-border rounded-lg pl-8 pr-24 py-4 font-mono text-base text-fg placeholder:text-fg-subtle transition-all duration-300 focus:(border-accent outline-none)" 71 + class="w-full bg-bg-subtle border border-border rounded-lg pl-8 pr-24 py-4 font-mono text-base text-fg placeholder:text-fg-subtle transition-border-color duration-300 focus:border-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50" 72 + autocomplete="off" 72 73 @input="handleSearch" 73 74 @focus="isSearchFocused = true" 74 75 @blur="isSearchFocused = false" ··· 76 77 77 78 <button 78 79 type="submit" 79 - class="absolute right-2 px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 active:scale-95" 80 + class="absolute right-2 px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-[background-color,transform] duration-200 hover:bg-fg/90 active:scale-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 80 81 > 81 82 {{ $t('search.button') }} 82 83 </button> ··· 89 90 <!-- Popular packages --> 90 91 <nav 91 92 :aria-label="$t('nav.popular_packages')" 92 - class="pb-20 text-center motion-safe:animate-fade-in motion-safe:animate-fill-both" 93 + class="pt-4 pb-36 sm:pb-40 text-center motion-safe:animate-fade-in motion-safe:animate-fill-both" 93 94 style="animation-delay: 0.3s" 94 95 > 95 96 <ul class="flex flex-wrap items-center justify-center gap-x-6 gap-y-3 list-none m-0 p-0">
+46
i18n/locales/en.json
··· 9 9 "non_affiliation_disclaimer": "not affiliated with npm, Inc.", 10 10 "trademark_disclaimer": "npm is a registered trademark of npm, Inc. This site is not affiliated with npm, Inc.", 11 11 "footer": { 12 + "about": "about", 12 13 "docs": "docs", 13 14 "source": "source", 14 15 "social": "social", ··· 492 493 "jsr": { 493 494 "title": "also available on JSR", 494 495 "label": "jsr" 496 + } 497 + }, 498 + "about": { 499 + "title": "About", 500 + "heading": "about", 501 + "meta_description": "npmx is a fast, modern browser for the npm registry. A better UX/DX for exploring npm packages.", 502 + "back_home": "back to home", 503 + "what_we_are": { 504 + "title": "What we are", 505 + "better_ux_dx": "better UX/DX", 506 + "admin_ui": "admin UI", 507 + "description": "npmx is a {betterUxDx} for the npm package registry and tooling. We provide a fast, modern interface for exploring packages, with features like dark mode, keyboard navigation, code browsing, and connections to alternative registries like {jsr}.", 508 + "admin_description": "We also aim to provide a better {adminUi} for managing your packages, teams, and organizations — all from the browser, powered by your local npm CLI." 509 + }, 510 + "what_we_are_not": { 511 + "title": "What we're not", 512 + "not_package_manager": "Not a package manager.", 513 + "not_registry": "Not a registry.", 514 + "registry_description": "We don't host packages. We're just a better way to browse them.", 515 + "package_managers_exist": "{already} {people} {building} {really} {cool} {package} {managers}.", 516 + "words": { 517 + "already": "There are", 518 + "people": "already", 519 + "building": "people", 520 + "really": "building", 521 + "cool": "really", 522 + "package": "cool", 523 + "managers": "package managers" 524 + } 525 + }, 526 + "vision": { 527 + "title": "Vision", 528 + "speed_first": "Speed first", 529 + "speed_first_description": "Layout shift, flakiness, and slowness is The Worst. We want everything to be fast, whether searching, filtering, or navigating.", 530 + "url_compatible": "URL compatible", 531 + "url_compatible_description": "Replace {npmjs} with {npmx} in any URL and it should work, providing the same information with a better experience.", 532 + "simplicity": "Simplicity", 533 + "simplicity_description": "No noise, cluttered display, or confusing UI." 534 + }, 535 + "open_source": { 536 + "title": "Open source", 537 + "description": "npmx is fully open source. Check out the {github}, join the {discord}, or follow us on {bluesky}.", 538 + "github": "source code on GitHub", 539 + "discord": "community on Discord", 540 + "bluesky": "Bluesky" 495 541 } 496 542 }, 497 543 "header": {
+47
i18n/locales/fr.json
··· 9 9 "non_affiliation_disclaimer": "non affilié à npm, Inc.", 10 10 "trademark_disclaimer": "npm est une marque déposée de npm, Inc. Ce site n'est pas affilié à npm, Inc.", 11 11 "footer": { 12 + "about": "à propos", 13 + "docs": "docs", 12 14 "source": "source", 13 15 "social": "réseaux sociaux", 14 16 "chat": "espace de discussion" ··· 481 483 "jsr": { 482 484 "title": "aussi disponible sur JSR", 483 485 "label": "jsr" 486 + } 487 + }, 488 + "about": { 489 + "title": "À propos", 490 + "heading": "à propos", 491 + "meta_description": "npmx est un navigateur rapide et moderne pour le registre npm. Une meilleure UX/DX pour explorer les paquets npm.", 492 + "back_home": "retour à l'accueil", 493 + "what_we_are": { 494 + "title": "Ce que nous sommes", 495 + "better_ux_dx": "meilleure UX/DX", 496 + "admin_ui": "interface d'administration", 497 + "description": "npmx est une {betterUxDx} pour le registre npm et ses outils. Nous fournissons une interface rapide et moderne pour explorer les paquets, avec des fonctionnalités comme le mode sombre, la navigation au clavier, la visualisation du code, et des connexions à des registres alternatifs comme {jsr}.", 498 + "admin_description": "Nous visons également à fournir une meilleure {adminUi} pour gérer vos paquets, équipes et organisations — le tout depuis le navigateur, alimenté par votre CLI npm local." 499 + }, 500 + "what_we_are_not": { 501 + "title": "Ce que nous ne sommes pas", 502 + "not_package_manager": "Pas un gestionnaire de paquets.", 503 + "not_registry": "Pas un registre.", 504 + "registry_description": "Nous n'hébergeons pas de paquets. Nous sommes juste une meilleure façon de les parcourir.", 505 + "package_managers_exist": "{already} {people} {building} {really} {cool} {package} {managers}.", 506 + "words": { 507 + "already": "Il y a", 508 + "people": "déjà", 509 + "building": "des gens", 510 + "really": "qui créent", 511 + "cool": "de vraiment", 512 + "package": "super", 513 + "managers": "gestionnaires de paquets" 514 + } 515 + }, 516 + "vision": { 517 + "title": "Vision", 518 + "speed_first": "La vitesse d'abord", 519 + "speed_first_description": "Les décalages de mise en page, l'instabilité et la lenteur sont le pire. Nous voulons que tout soit rapide, que ce soit la recherche, le filtrage ou la navigation.", 520 + "url_compatible": "Compatible avec les URL", 521 + "url_compatible_description": "Remplacez {npmjs} par {npmx} dans n'importe quelle URL et cela devrait fonctionner, fournissant les mêmes informations avec une meilleure expérience.", 522 + "simplicity": "Simplicité", 523 + "simplicity_description": "Pas de bruit, d'affichage encombré ou d'interface confuse." 524 + }, 525 + "open_source": { 526 + "title": "Open source", 527 + "description": "npmx est entièrement open source. Consultez le {github}, rejoignez la {discord}, ou suivez-nous sur {bluesky}.", 528 + "github": "code source sur GitHub", 529 + "discord": "communauté sur Discord", 530 + "bluesky": "Bluesky" 484 531 } 485 532 }, 486 533 "header": {
+47
i18n/locales/it.json
··· 9 9 "non_affiliation_disclaimer": "non affiliato con npm, Inc.", 10 10 "trademark_disclaimer": "npm è un marchio registrato da npm, Inc. Questo sito non è affiliato con npm, Inc.", 11 11 "footer": { 12 + "about": "info", 13 + "docs": "docs", 12 14 "source": "codice", 13 15 "social": "social", 14 16 "chat": "chat" ··· 469 471 "jsr": { 470 472 "title": "disponibile anche su JSR", 471 473 "label": "jsr" 474 + } 475 + }, 476 + "about": { 477 + "title": "Info", 478 + "heading": "info", 479 + "meta_description": "npmx è un browser veloce e moderno per il registro npm. Una migliore UX/DX per esplorare i pacchetti npm.", 480 + "back_home": "torna alla home", 481 + "what_we_are": { 482 + "title": "Cosa siamo", 483 + "better_ux_dx": "migliore UX/DX", 484 + "admin_ui": "interfaccia di amministrazione", 485 + "description": "npmx è una {betterUxDx} per il registro npm e i suoi strumenti. Forniamo un'interfaccia veloce e moderna per esplorare i pacchetti, con funzionalità come la modalità scura, la navigazione da tastiera, la visualizzazione del codice e connessioni a registri alternativi come {jsr}.", 486 + "admin_description": "Miriamo anche a fornire una migliore {adminUi} per gestire i tuoi pacchetti, team e organizzazioni — tutto dal browser, alimentato dalla tua CLI npm locale." 487 + }, 488 + "what_we_are_not": { 489 + "title": "Cosa non siamo", 490 + "not_package_manager": "Non un gestore di pacchetti.", 491 + "not_registry": "Non un registro.", 492 + "registry_description": "Non ospitiamo pacchetti. Siamo solo un modo migliore per esplorarli.", 493 + "package_managers_exist": "{already} {people} {building} {really} {cool} {package} {managers}.", 494 + "words": { 495 + "already": "Ci sono", 496 + "people": "già", 497 + "building": "persone", 498 + "really": "che creano", 499 + "cool": "davvero", 500 + "package": "fantastici", 501 + "managers": "gestori di pacchetti" 502 + } 503 + }, 504 + "vision": { 505 + "title": "Visione", 506 + "speed_first": "Velocità prima di tutto", 507 + "speed_first_description": "I cambiamenti di layout, l'instabilità e la lentezza sono il peggio. Vogliamo che tutto sia veloce, che si tratti di ricerca, filtro o navigazione.", 508 + "url_compatible": "Compatibile con gli URL", 509 + "url_compatible_description": "Sostituisci {npmjs} con {npmx} in qualsiasi URL e dovrebbe funzionare, fornendo le stesse informazioni con un'esperienza migliore.", 510 + "simplicity": "Semplicità", 511 + "simplicity_description": "Niente rumore, display disordinato o interfaccia confusa." 512 + }, 513 + "open_source": { 514 + "title": "Open source", 515 + "description": "npmx è completamente open source. Dai un'occhiata al {github}, unisciti alla {discord}, o seguici su {bluesky}.", 516 + "github": "codice sorgente su GitHub", 517 + "discord": "community su Discord", 518 + "bluesky": "Bluesky" 472 519 } 473 520 }, 474 521 "header": {
+47
i18n/locales/zh-CN.json
··· 9 9 "non_affiliation_disclaimer": "不与 npm, Inc. 有任何隶属关系", 10 10 "trademark_disclaimer": "npm 是 npm, Inc. 的注册商标。本网站不与 npm, Inc. 有任何隶属关系。", 11 11 "footer": { 12 + "about": "关于", 13 + "docs": "文档", 12 14 "source": "源码", 13 15 "social": "社媒", 14 16 "chat": "聊天" ··· 491 493 "jsr": { 492 494 "title": "也适用于 JSR", 493 495 "label": "jsr" 496 + } 497 + }, 498 + "about": { 499 + "title": "关于", 500 + "heading": "关于", 501 + "meta_description": "npmx 是一个快速、现代的 npm 仓库浏览器。为探索 npm 包提供更好的用户体验和开发者体验。", 502 + "back_home": "返回首页", 503 + "what_we_are": { 504 + "title": "我们是什么", 505 + "better_ux_dx": "更好的用户体验和开发者体验", 506 + "admin_ui": "管理界面", 507 + "description": "npmx 为 npm 包仓库及其工具提供{betterUxDx}。我们提供快速、现代的界面来探索包,具有深色模式、键盘导航、代码浏览以及与 {jsr} 等替代仓库的连接等功能。", 508 + "admin_description": "我们还致力于提供更好的{adminUi}来管理您的包、团队和组织——全部在浏览器中完成,由您本地的 npm CLI 驱动。" 509 + }, 510 + "what_we_are_not": { 511 + "title": "我们不是什么", 512 + "not_package_manager": "不是包管理器。", 513 + "not_registry": "不是仓库。", 514 + "registry_description": "我们不托管包。我们只是一种更好的浏览方式。", 515 + "package_managers_exist": "{already}{people}{building}{really}{cool}{package}{managers}。", 516 + "words": { 517 + "already": "已经有", 518 + "people": "很多", 519 + "building": "人在", 520 + "really": "开发", 521 + "cool": "非常", 522 + "package": "棒的", 523 + "managers": "包管理器" 524 + } 525 + }, 526 + "vision": { 527 + "title": "愿景", 528 + "speed_first": "速度优先", 529 + "speed_first_description": "布局偏移、不稳定和缓慢是最糟糕的。无论是搜索、筛选还是导航,我们都希望一切都快速。", 530 + "url_compatible": "URL 兼容", 531 + "url_compatible_description": "将任何 URL 中的 {npmjs} 替换为 {npmx},它应该可以工作,提供相同的信息和更好的体验。", 532 + "simplicity": "简洁", 533 + "simplicity_description": "没有噪音、杂乱的显示或令人困惑的界面。" 534 + }, 535 + "open_source": { 536 + "title": "开源", 537 + "description": "npmx 完全开源。查看 {github},加入 {discord},或在 {bluesky} 上关注我们。", 538 + "github": "GitHub 上的源代码", 539 + "discord": "Discord 社区", 540 + "bluesky": "Bluesky" 494 541 } 495 542 }, 496 543 "header": {