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

folio-shell

v1.4.0

Published

Shared React UI — design tokens, layout, hub navigation shell

Readme

folio-shell

Shared React UI for multi-app personal sites: design tokens, layout primitives, hub navigation shell, and icons.

GitHub repo: RoyCrivolotti/folio-shell
(Old URLs site-ui and folio-ui redirect here after renames.)

Proprietary — see LICENSE. Source is public for transparency.

Consumed by landing, admin-hub, expense-tracker, and oncall-tracker:

npm install folio-shell

Peer dependencies

react and react-dom (^19) are peer dependencies. Install them in the consumer app if they are not already present:

npm install react react-dom folio-shell

Usage

Design tokens

Import once at app entry (before app CSS) so components can use var(--…):

// main.tsx
import 'folio-shell/theme/tokens.css'

Tokens define colours, spacing, typography, and light/dark scheme variables. Apps add local CSS modules on top; do not redefine palette values outside tokens.css.

Layout

Full-viewport page shell for landing and hub surfaces:

import { Layout } from 'folio-shell'

export function MyPage() {
  return (
    <Layout>
      <h1>Title</h1>
      <p>Content centred in a single column.</p>
    </Layout>
  )
}

Pass centered={false} for full-width content, or className for layout tweaks (e.g. staging banner offset).

Card

Tappable resource link for hub grids:

import { Card, WalletIcon } from 'folio-shell'

<Card
  href="https://expenses.example.com"
  title="Expense Tracker"
  description="Budgets, transactions, and cash flow."
  icon={<WalletIcon />}
/>

Set external for links that open in a new tab.

Hub menu

Cross-app navigation drawer. Wrap the page (or shell) in HubMenuRoot, place one or more triggers, and pass hub destinations as navItems:

import { HubMenuRoot, HubMenuTrigger, getSiteUrls, HomeIcon, WalletIcon } from 'folio-shell'
import type { HubNavItem } from 'folio-shell'

const navItems: HubNavItem[] = [
  { href: '/', label: 'Hub', Icon: HomeIcon },
  { href: getSiteUrls().expenses, label: 'Expenses', Icon: WalletIcon },
]

export function AppShell({ children }: { children: React.ReactNode }) {
  return (
    <HubMenuRoot anchor="inline" navItems={navItems}>
      <header>
        <HubMenuTrigger iconOnly />
        <h1>My app</h1>
      </header>
      {children}
    </HubMenuRoot>
  )
}

For fixed-position report pages, use anchor="fixed", triggerVariant="onLight", and HubMenuTriggerFixed instead of inline triggers.

Hub menu shows Sign out by default (/cdn-cgi/access/logout). Pass logoutHref={null} on public pages (e.g. landing).

getSiteUrls()

Returns cross-app URLs from Vite env at build time:

import { getSiteUrls } from 'folio-shell'

const { landing, adminHub, expenses, oncall } = getSiteUrls()

See Environment variables below.

Environment variables (consumers)

Hub cross-links read build-time Vite env:

| Variable | Purpose | | --- | --- | | VITE_LANDING_URL | Public landing URL | | VITE_ADMIN_HUB_URL | Private admin hub URL | | VITE_EXPENSES_URL | Expense tracker URL | | VITE_ONCALL_URL | On-call tracker URL | | VITE_APP_ENV | Set to staging on dev/staging builds (enables StagingFrame banner) | | VITE_STAGING_PRODUCTION_URL | Production URL linked from the staging banner |

Commit .env.production in each consumer app so CI/production builds embed the correct hub URLs. getSiteUrls() also has production fallbacks as a safety net.

Profile content and private-area links live in each app, not in this package.

Release workflow

Publishing is automated when you create a GitHub Release (tag push → release published). CI runs verify, then npm publish via .github/workflows/publish.yml.

  1. Change and verify here: npm run verify
  2. Commit and push to main
  3. Tag and push: git tag v1.x.y && git push origin v1.x.y
  4. Create a GitHub Release for that tag (Publish release). CI publishes to npm.
  5. Bump "folio-shell" semver in consumer package.json files

Manual fallback (if CI publish fails or you need a one-off retry):

cd ~/Repos/personal/folio-shell
npm publish --access public

Requires NPM_TOKEN locally or an npm login with publish rights.

Current version: 1.0.4

Local development (sibling checkout)

From ~/Repos/personal:

./link-folio-shell.sh

Verify

npm run verify   # lint + typecheck + test

License

Proprietary — see LICENSE. Source is public for transparency; unauthorized copying, modification, or distribution is prohibited.