npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@loodi/ui

v0.9.0

Published

Presentation-only React design system for the Loodi ecosystem.

Readme

@loodi/ui

Design system React public de Loodi : composants présentationnels et tokens partagés. Les composants reçoivent exclusivement des props et des callbacks ; le bridge, le router, les stores, Dexie et Capacitor restent dans l'application consommatrice.

import { BottomNav, MiniHeader } from '@loodi/ui'
import '@loodi/ui/styles.css'

L'import historique reste disponible : styles.css est compilé et inclut les tokens ainsi que le CSS des trois composants. Aucun réglage Tailwind n'est requis côté consommateur.

Pour une PWA optimisée, charger les seuls composants utilisés :

import { MiniHeader } from '@loodi/ui/mini-header'
import { BottomNav } from '@loodi/ui/bottom-nav'
import { Launcher } from '@loodi/ui/launcher'

import '@loodi/ui/tokens.css'
import '@loodi/ui/mini-header.css'
import '@loodi/ui/bottom-nav.css'
import '@loodi/ui/launcher.css'

Les tokens sont disponibles sans React via @loodi/ui/tokens.css. Le fichier @loodi/ui/tokens.dtcg.json est l'export DTCG destiné à Penpot/Open Design. Les deux artefacts sont générés depuis src/tokens.source.json ; ne pas les modifier à la main.

Les bundles ESM externalisent react, react-dom et lucide-react.

MiniHeader consomme les SVG versionnés de @loodi/assets. Il n’attend aucun chemin à la racine de l’application hôte. Une PWA standalone peut sélectionner une base d’assets explicite :

<MiniHeader assetBaseUrl="https://assets.example.com/loodi/v1" {...props} />

Sans assetBaseUrl, les assets sont inclus dans le livrable du consommateur. Le logo occupe le même slot que le retour ; le wordmark et le nom de module restent visibles sur les deux types de page.

AuthBottomSheet et AccountBottomSheet

Les sheets d’authentification sont des composants de présentation contrôlés. Elles n’importent ni Supabase, ni clé, ni routeur et ne persistent aucune donnée personnelle : seuls les brouillons e-mail/pseudo existent pendant leur ouverture.

import { AuthBottomSheet, AccountBottomSheet } from '@loodi/ui/auth-bottom-sheet'
import '@loodi/ui/auth-bottom-sheet.css'

const auth = useAuth() // fourni par @loodi/auth dans l’application hôte

<AuthBottomSheet
  open={authOpen}
  state={auth.state === 'handle-required' ? 'handle-required' : 'anonymous'}
  onClose={() => setAuthOpen(false)}
  onSignInWithGoogle={auth.signInWithGoogle}
  onSignInWithMagicLink={auth.signInWithMagicLink}
  onCompleteHandle={auth.completeHandle}
  onAbandonIncompleteAccount={auth.abandonIncompleteAccount}
/>
<AccountBottomSheet
  open={accountOpen}
  playerName={auth.session?.handle}
  onClose={() => setAccountOpen(false)}
  onOpenAccount={() => navigate('/account')}
  onSignOut={auth.signOut}
/>

AuthBottomSheet couvre Google, lien magique, erreurs, succès et le pseudo requis ; AccountBottomSheet couvre l’accès au compte et la confirmation de déconnexion. onOverlayChange permet au host de masquer sa navigation pendant une sheet. One relie onOpenAccount à sa page partagée ; une app standalone le relie à /account. styles.css inclut aussi ces styles.

BottomNav

Par défaut, BottomNav conserve le modèle historique : quatre tabs au maximum et le bouton Applications/Loodi. onAppsTap reste alors requis.

<BottomNav
  tabs={tabs}
  activeTab={activeTab}
  onTabTap={setActiveTab}
  onAppsTap={openLauncher}
/>

Pour une PWA sans launcher, showApps={false} affiche jusqu’à cinq onglets fournis et rend onAppsTap optionnel. Les icônes Lucide settings, library-big, user et users, ainsi que les icônes de navigation Loodi, sont reconnues.

<BottomNav
  showApps={false}
  tabs={[{ id: 'settings', icon: 'settings', label: 'Paramètres', badgeCount: 3 }]}
  onTabTap={setActiveTab}
  onSwipeUp={openSheet}
/>

badgeCount s’affiche seulement au-dessus de zéro et est plafonné visuellement à 99+ ; le libellé accessible conserve le compte exact. onSwipeUp est un callback générique optionnel, déclenché par un glissement vertical vers le haut d’au moins 40px. Tous les styles de la navigation, y compris le badge (status-danger / status-on-solid), sont fournis par @loodi/ui/bottom-nav.css : aucune classe Tailwind hôte n’est requise.

La version publiée suit semver. Les changements incompatibles de props, de comportement ou de tokens imposent une version majeure.