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

@the-portland-company/shell

v0.43.1

Published

Shared chrome (header, sidebar, footer, theme, auth) for politogy apps. Drop into any Vite SPA to inherit the politogy look and signed-in user.

Downloads

11,007

Readme

@the-portland-company/shell

Shared chrome for politogy apps. One install, one wrapper, identical look.

Every politogy product (Email Blast, Contacts, Forms, future apps…) installs this package and gets the full branded experience — sidebar with VRM logo, organization switcher, mode selector, full nav list, header with notifications and support, branded footer with commit info — without rebuilding any of it. Path-based routing lets multiple separately-deployed Vite SPAs feel like a single continuous app on app.politogy.com.

v0.3.x is a major rewrite. See the CHANGELOG for the chrome component, hook, and prop additions over v0.2.x. The minimum viable boot below works for new apps; existing v0.2.x consumers can keep using OrgSelector, useShellAuth, etc. without changes.


Install

Pin peer dep versions explicitly — Vite scaffolds React 19 + Chakra v3 by default, neither of which the shell supports:

npm install @the-portland-company/shell \
            react@^18 react-dom@^18 \
            @chakra-ui/react@^2.8 @emotion/react@^11 @emotion/styled@^11 \
            framer-motion@^11 \
            @supabase/supabase-js@~2.95 \
            react-router-dom@^6 react-icons@^5

@the-portland-company/devnotes is optional — only needed if you want the dev-notes menu in the header. Skip it if your app doesn't use it.


Minimum viable boot

The simplest possible startup renders the branded chrome with empty defaults — the sidebar appears, the header renders, but the org switcher / mode selector / nav list show "no data" states until you wire them up via <ShellChrome> (next section).

// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import { ShellProvider, AppLayout } from '@the-portland-company/shell'
import '@the-portland-company/shell/chrome.css'
import { createClient } from '@supabase/supabase-js'
import App from './App'

const supabase = createClient(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_ANON_KEY,
)

ReactDOM.createRoot(document.getElementById('root')!).render(
  <ShellProvider currentApp="email" supabaseClient={supabase}>
    <BrowserRouter>
      <AppLayout>
        <App />
      </AppLayout>
    </BrowserRouter>
  </ShellProvider>,
)

<AppLayout> composes the shell <Header>, <Sidebar>, your routed content, and <Footer>. <ShellProvider> owns the Supabase auth lifecycle and exposes useShellAuth() for status / user / sign-out.


Real-world boot: feeding the chrome real data

Most apps have an <AuthProvider>, <OrganizationProvider>, <ModeProvider>, etc. that live below <ShellProvider> in the tree. To push their data up into the shell's chrome contexts, drop a <ShellChrome> binding component as deep in the tree as the data is available:

import {
  ShellProvider,
  ShellChrome,
  AppLayout,
} from '@the-portland-company/shell'

function ChromeBridge({ children }) {
  const { currentMode, switchMode, getModeConfig, getAvailableModes } = useMode()
  const { currentOrg, organizations, switchOrganization } = useOrganization()
  const { linkedAccounts, ... } = useLinkedAccounts()
  // …compute the nav-items list for the active mode here…
  return (
    <ShellChrome
      mode={{ currentMode, modes: getAvailableModes(), switchMode, getModeConfig }}
      organization={{ currentOrg, organizations, switchOrganization }}
      linkedAccounts={{ linkedAccounts, switchToAccount, onAddAccount, onRemoveAccount }}
      navItems={navItems}
      role={{ activeRoleConfig, isSuperAdmin }}
      footer={{ links, commit, version, releaseName, environmentLabel }}
      support={{ submitSupportRequest }}
      brandLogoSrc="/brand/logos/email-mode-logo.png"
      headerIconsSlot={<MyAppSpecificIcons />}
      userAvatarUrl={profile.avatar_url ?? storedMemojiUrl ?? defaultAvatarUrl}
      myProfileHref="/my-profile"
      organizationSettingsHref={`/organization-settings?org=${currentOrg.id}`}
    >
      {children}
    </ShellChrome>
  )
}

// Then in main.tsx:
<ShellProvider currentApp="email" supabaseClient={supabase}>
  <BrowserRouter>
    <AuthProvider>
      <OrganizationProvider>
        <ModeProvider>
          <ChromeBridge>
            <AppLayout>
              <Routes>…</Routes>
            </AppLayout>
          </ChromeBridge>
        </ModeProvider>
      </OrganizationProvider>
    </AuthProvider>
  </BrowserRouter>
</ShellProvider>

Reference implementation: politogy-vrm's react/app/src/providers/ShellChromeBridge.tsx (~600 lines, every chrome wiring pattern). Copy as a starting point for new apps.

All <ShellChrome> props are optional — only supply what your app has. The chrome gracefully omits the bits it doesn't get data for (e.g., no support prop → no support icon rendered).


What the shell exports

Components

| Export | Use | |---|---| | <ShellProvider> | Top-level provider. Wraps Chakra + auth + meta contexts. | | <ShellChrome> | Mid-tree binding component. Feeds chrome contexts from app data. | | <AppLayout> | Composes Header + Sidebar + main content + Footer. | | <Header> | Header bar (logo, page title, breadcrumbs, icon stack, user menu). | | <Sidebar> | Sidebar (branded logo, org pill, mode pill, nav list, footer). | | <Footer> | Below main content. Usually not rendered separately. | | <UserMenu> | Avatar dropdown (profile, theme, sign out, switch account). | | <OrgPill> (alias <OrgSelector>) | Organization switcher pill rendered in the sidebar. | | <ModePill> | Mode (Relationship / Campaign / Petition) switcher. | | <NavItem> | Single sidebar nav row with active state + hover gradient. | | <SupportRequestButton> | Header life-buoy icon that opens a support modal. | | <BrandLogo> | <img> wrapper for the branded mode logo. | | <BrandIcon name="..."> | Renders /brand/icons/<name>.svg from your public/. | | <CommitCopyButton> | Footer commit/version display with copy-to-clipboard. | | <Card>, <PageContainer>, <PageHeader>, <BreadcrumbBar>, <HeaderTabBar> | Page-level layout primitives. | | <GlobalUiIdProvider> | Assigns stable UI IDs (for testing/analytics). |

Hooks

| Hook | Returns | |---|---| | useShellAuth() | { status, user, session, signOut } | | useShellOrganization() | { currentOrg, organizations, switchOrganization, createOrgHref } \| null | | useShellMode() | { currentMode, modes, switchMode, getModeConfig } \| null | | useShellNavItems() | { items: ShellNavItem[] } \| null | | useShellLinkedAccounts() | { linkedAccounts, switchToAccount, onAddAccount, onRemoveAccount } \| null | | useShellSupport() | { submitSupportRequest } \| null | | useShellRole() | { activeRoleConfig, isSuperAdmin } \| null | | useShellFooter() | { links, version, commit, releaseName, … } \| null | | useShellNavigationPreference() | { showSubMenu } \| null | | useShellChrome() | Chrome configuration (devNotesMenu, myProfileHref, userAvatarUrl, pageTitle, breadcrumbs, headerActions, etc.) | | useAppRegistry(), useCurrentApp() | App switcher metadata for cross-app speculation rules. |

Helpers

normalizeHexColor, lightenHexColor, hexToRgba, getOrganizationBrandColor, getOrganizationBadgeLetters, getUserDisplayName.

Theme

politogyTheme — Chakra theme with brand palette, mode-aware semantic tokens, and component overrides.


CSS imports

import '@the-portland-company/shell/chrome.css'      // :root design tokens (--app-color-brand-*, --mode-*, --app-tab-*, --form-control-*)
import '@the-portland-company/shell/css'             // view-transitions CSS for cross-app polish

chrome.css is required for theme variables. css (view-transitions) is optional polish.


Mode-aware navigation (Campaign Mode)

PolitogyAppFrame and standardPolitogyNav render a different left-nav tree per operating Mode — and an app passes nothing to select it. Which tree an app renders is derived from the app's own mode in the POLITOGY_APPS registry:

  • Unscoped apps (no mode — forms / surveys / polls / contacts / vrm) render the Relationship tree, byte-for-byte as before, with an entitlement-driven Mode pill.
  • Campaign apps (a2p, phonebank, canvass, signs, all mode: 'campaign') render the Campaign tree (Dashboard, Voter Contact, then the launched feature apps) and a static Campaign pill.
  • Petitions (mode: 'petition') renders a minimal Petition tree.

Campaign features ship incrementally. CAMPAIGN_FEATURE_AVAILABILITY (exported from @the-portland-company/shell/native) gates each feature: a disabled one is omitted from the nav, and its flag flips to true in a patch release as the app launches. Defaults: Polling Engine and Tribes on; A2P, Phone Banking, Field Canvassing, Sign Mapping off.

Cross-app links in the Campaign/Petition trees carry the active org as ?org=<last6> — the same convention the Mode switcher and My Account menu use — so the destination app opens on the same org. When the chrome API grants more than one Mode (scope.modes), the pill becomes a switcher whose selection navigates to that Mode's home carrying the active org.

Multi-SPA routing on app.politogy.com

Multiple politogy apps live behind one domain via a Cloudflare Worker edge router (in packages/edge-router of the monorepo).

When you deploy a new app to Cloudflare Pages, add its path prefix to the edge router's routes.ts:

{
  pathPrefix: '/email',
  origin: 'https://politogy-email.pages.dev',
}

After deploy, users hitting app.politogy.com/email/* get transparently proxied to your app. Other paths keep going to whichever app owns them. The shared shell + same Supabase session means it feels like one app.


Service worker (optional polish)

The package ships a precache service worker that caches the shell chrome on first visit so cross-app navigation feels instant.

// scripts/copy-shell-sw.mjs
import { copyFile } from 'node:fs/promises'
await copyFile(
  'node_modules/@the-portland-company/shell/dist/shell-precache.worker.js',
  'public/sw-shell.js',
)

Wire it into your build ("postinstall": "node scripts/copy-shell-sw.mjs") and call registerShellPrecache() once on app boot.


Speculation Rules (optional polish)

Cross-app prerendering hints for the browser:

import { useAppRegistry, useCurrentApp, buildSpeculationRules } from '@the-portland-company/shell'

function SpeculationRules() {
  const registry = useAppRegistry()
  const current = useCurrentApp()
  const json = buildSpeculationRules(current, registry)
  if (!json) return null
  return <script type="speculationrules" dangerouslySetInnerHTML={{ __html: json }} />
}

Render once near the app root.


Reference + support

  • Reference bridge: politogy-vrm/react/app/src/providers/ShellChromeBridge.tsx — full chrome wiring for the main politogy app.
  • Architectural decisions, gotchas, session log: politogy-vrm/docs/superpowers/.
  • Type definitions: node_modules/@the-portland-company/shell/dist/index.d.ts — every prop and hook is fully typed.
  • CHANGELOG: CHANGELOG.md — every export added per version.

Questions or missing features: file an issue or ping the politogy team.