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

@glamcor/dna-shared-nav

v1.0.12

Published

Shared navigation component for DNA microsites

Readme

@glamcor/dna-shared-nav

Plans & status: Work on this repo is planned in erik-plans (approved plans on main); check its status branch to see what's in flight.

Shared navigation package for DNA microsites. Provides a consistent two-row navigation bar across all DNA applications: a top header row (logo, inter-app links, avatar) and an app-specific subnav row (app name, page links, pinned jobs).

Current version: 1.0.12


Installation

npm install @glamcor/dna-shared-nav

The package requires React 18 as a peer dependency.


Exported Components

DNANavigation (primary)

The main combined component. Renders DNAHeader + AppSubnav stacked vertically inside a sticky div.dna-navigation wrapper (z-index 100).

DNAHeader

The top header bar: DNA logo (links to dashboard), inter-app navigation links, and the avatar menu (or a "Sign In" link when no user is provided).

AppSubnav

The second row: app name label (with a right border separator), app-specific page links, and a pinned jobs carousel anchored to the right.

AvatarMenu

Standalone avatar button with a click-outside-dismissible dropdown. Shows user name, email, and links to Profile, Settings, Team, Documentation, and Support. Contains a "Sign Out" button. When onLogout is not provided, clicking Sign Out navigates to /api/auth/logout.

PinnedJobs

Standalone pinned jobs carousel. Renders nothing when jobs is empty. Displays up to 2 job pills at a time; carousel nav arrows appear when there are more than 2 jobs. Each pill shows a circular SVG progress ring, the app name (colored with appColor), the job name, and an unpin button.


TypeScript Interfaces

All interfaces are exported from the package root.

interface DNAUser {
  id: string;
  email: string;
  name: string;
  role?: 'superadmin' | 'admin' | 'editor' | 'viewer';
  avatar?: string;
}

interface DNANavItem {
  name: string;
  href: string;
  requiredRole?: 'viewer' | 'editor' | 'admin' | 'superadmin';
  hasNotification?: boolean;
}

interface AppSubnavItem {
  name: string;
  href: string;
  isActive?: boolean;
}

interface PinnedJob {
  id: string;
  appName: string;
  appColor?: string;
  jobName: string;
  progress: number;  // 0–100
  meta?: string;
}

interface DNANavigationProps {
  user: DNAUser | null;
  currentApp?: string;
  appName: string;
  headerItems?: DNANavItem[];
  subnavItems: AppSubnavItem[];
  pinnedJobs?: PinnedJob[];
  logoSrc?: string;
  onLogout?: () => void;
  onUnpinJob?: (jobId: string) => void;
}

interface DNAHeaderProps {
  user: DNAUser | null;
  currentApp?: string;   // defaults to 'Dashboard'
  items?: DNANavItem[];  // defaults to DEFAULT_NAV_ITEMS
  logoSrc?: string;
  onLogout?: () => void;
}

interface AppSubnavProps {
  appName: string;
  items: AppSubnavItem[];
  pinnedJobs?: PinnedJob[];
  onUnpinJob?: (jobId: string) => void;
}

interface AvatarMenuProps {
  userName: string;
  userEmail: string;
  initials: string;    // pre-computed, e.g. "JD"
  onLogout?: () => void;
}

interface PinnedJobsProps {
  jobs: PinnedJob[];
  onUnpin?: (jobId: string) => void;
}

Role-based nav filtering

DNAHeader filters headerItems using a role hierarchy: viewer < editor < admin < superadmin. A nav item with requiredRole set is hidden unless the current user's role meets or exceeds it. Items without requiredRole are always visible. When user is null and an item has requiredRole, the item is hidden.


Props Reference: DNANavigation

| Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | user | DNAUser \| null | Yes | — | Current user. Pass null to show a "Sign In" link instead of avatar. | | currentApp | string | No | 'Dashboard' | Name of the active app. Must match a nav item's name exactly to highlight it. | | appName | string | Yes | — | Label shown at the left of the subnav row. | | headerItems | DNANavItem[] | No | Default 15-item list | Override the inter-app nav links. | | subnavItems | AppSubnavItem[] | Yes | — | Page links for the subnav row. | | pinnedJobs | PinnedJob[] | No | [] | Jobs to display in the pinned jobs carousel. | | logoSrc | string | No | CloudFront CDN URL | Custom logo image URL. | | onLogout | () => void | No | Navigates to /api/auth/logout | Called when the user clicks "Sign Out". | | onUnpinJob | (jobId: string) => void | No | — | Called with the job's id when the unpin button is clicked. |


Default Nav Items

When headerItems is not provided, DNAHeader renders these 15 links in order. Each reads its URL from an environment variable at build time, falling back to the path listed.

| Name | Environment Variable | Fallback | |------|---------------------|----------| | Dashboard | NEXT_PUBLIC_DNA_DASHBOARD_URL | / | | SPOT | NEXT_PUBLIC_SPOT_URL | /spot | | Nitrogen | NEXT_PUBLIC_DNA_NITROGEN_URL | /nitrogen | | Phosphor | NEXT_PUBLIC_DNA_PHOSPHOR_URL | /phosphor | | Water | NEXT_PUBLIC_DNA_WATER_URL | /water | | Heat | NEXT_PUBLIC_DNA_HEAT_URL | /heat | | Methane | NEXT_PUBLIC_DNA_METHANE_URL | /methane | | Hydrogen | NEXT_PUBLIC_DNA_HYDROGEN_URL | /hydrogen | | Oxygen | NEXT_PUBLIC_DNA_OXYGEN_URL | /oxygen | | Ammonia | NEXT_PUBLIC_DNA_AMMONIA_URL | /ammonia | | Carbon | NEXT_PUBLIC_DNA_CARBON_URL | /carbon | | Lightning | NEXT_PUBLIC_DNA_LIGHTNING_URL | /lightning | | Sulfur | NEXT_PUBLIC_DNA_SULFUR_URL | /sulfur | | Formic | NEXT_PUBLIC_DNA_FORMIC_URL | /formic | | Clay | NEXT_PUBLIC_DNA_CLAY_URL | /clay |

The logo also links to NEXT_PUBLIC_DNA_DASHBOARD_URL || '/'.


Environment Variables

Add these to .env.local in each microsite. All are optional — omitting a variable causes that nav link to fall back to the relative path shown above, which will only work correctly from the target app itself.

NEXT_PUBLIC_DNA_DASHBOARD_URL=https://dna-dashboard.vercel.app
NEXT_PUBLIC_SPOT_URL=https://spot.vercel.app
NEXT_PUBLIC_DNA_NITROGEN_URL=https://dna-nitrogen.vercel.app
NEXT_PUBLIC_DNA_WATER_URL=https://dna-water.vercel.app
NEXT_PUBLIC_DNA_HEAT_URL=https://dna-heat.vercel.app
NEXT_PUBLIC_DNA_METHANE_URL=https://dna-methane.vercel.app
NEXT_PUBLIC_DNA_HYDROGEN_URL=https://dna-hydrogen.vercel.app
NEXT_PUBLIC_DNA_OXYGEN_URL=https://dna-oxygen.vercel.app
NEXT_PUBLIC_DNA_AMMONIA_URL=https://dna-ammonia.vercel.app
NEXT_PUBLIC_DNA_CARBON_URL=https://dna-carbon.vercel.app
NEXT_PUBLIC_DNA_LIGHTNING_URL=https://dna-lightning.vercel.app
NEXT_PUBLIC_DNA_PHOSPHOR_URL=https://dna-phosphor.vercel.app
NEXT_PUBLIC_DNA_SULFUR_URL=https://dna-sulfur.vercel.app
NEXT_PUBLIC_DNA_FORMIC_URL=https://formic.imek-dev.com
NEXT_PUBLIC_DNA_CLAY_URL=https://clay.imek-dev.com

App Colors (for PinnedJob.appColor)

The appColor field on PinnedJob controls the progress ring stroke color and the app name label color inside each pinned job pill. Use the approved app colors from The DNA UI Book §6.2. In apps that load @glamcor/dna-ui, pass the token, for example var(--app-nitrogen).

| App | Token | Color | |-----|-------|-------| | Dashboard | --app-dashboard | #facc15 | | SPOT | --app-spot | #f472b6 | | Water | --app-water | #38bdf8 | | Nitrogen | --app-nitrogen | #34d399 | | Methane | --app-methane | #fb923c | | Hydrogen | --app-hydrogen | #22d3d8 | | Carbon | --app-carbon | #94a3b8 | | Lightning | --app-lightning | #fbbf24 | | Heat | --app-heat | #f43f5e | | Oxygen | --app-oxygen | #60a5fa | | Ammonia | --app-ammonia | #a3e635 | | Phosphor | --app-phosphor | #22c55e | | Sulfur | --app-sulfur | #2dd4bf | | Formic | --app-formic | #818cf8 | | Ultraviolet | --app-ultraviolet | #e879f9 | | Clay | --app-clay | #d4a373 |


Integration Guide

Follow these steps to add the shared nav to a new Next.js microsite.

1. Install the package

npm install @glamcor/dna-shared-nav

2. Add environment variables

Add the inter-app URLs to .env.local (see the Environment Variables section above).

3. Import styles globally

Import the stylesheet once. The correct place is the admin layout, not the root layout, unless the nav appears on all routes.

import '@glamcor/dna-shared-nav/dist/styles.css';

The package exports the stylesheet at two paths for compatibility:

  • @glamcor/dna-shared-nav/dist/styles.css
  • @glamcor/dna-shared-nav/styles.css

4. Add the nav to the admin layout

Create or edit src/app/admin/layout.tsx. The component must be a Client Component because DNANavigation uses 'use client' internally.

'use client';

import { usePathname } from 'next/navigation';
import { DNANavigation, type AppSubnavItem, type DNAUser } from '@glamcor/dna-shared-nav';
import '@glamcor/dna-shared-nav/dist/styles.css';
import { useAuth } from '@/contexts/AuthContext'; // your auth context

// Define subnav pages for this app
const SUBNAV_PAGES = [
  { name: 'Dashboard', href: '/admin' },
  { name: 'Page Two', href: '/admin/page-two' },
];

export default function AdminLayout({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();
  const { user, logout } = useAuth();

  // Mark the active subnav item based on current path
  const subnavItems: AppSubnavItem[] = SUBNAV_PAGES.map((item) => ({
    ...item,
    isActive:
      pathname === item.href ||
      (item.href !== '/admin' && pathname?.startsWith(item.href)),
  }));

  // Map your auth user to DNAUser shape
  const dnaUser: DNAUser | null = user
    ? {
        id: user.id,
        email: user.email,
        name: user.name || user.email,
        role: user.role,
      }
    : null;

  return (
    <div style={{ minHeight: '100vh', background: '#0a0a0a' }}>
      <DNANavigation
        user={dnaUser}
        currentApp="MyApp"       // must match exactly one name in the default nav items
        appName="MyApp"          // label shown in the subnav row
        subnavItems={subnavItems}
        onLogout={logout}
      />
      <main>{children}</main>
    </div>
  );
}

5. Account for nav height in layout

The navigation occupies a total height of 80px: the header row is 44px and the subnav row is 36px. When computing full-viewport heights for content areas, subtract 80px:

// Example with MUI Box
<Box sx={{ minHeight: 'calc(100vh - 80px)' }}>
  {children}
</Box>

6. Pinned jobs (optional)

To show pinned background jobs in the subnav, maintain a list of PinnedJob objects in state and pass them via pinnedJobs. Handle removal via onUnpinJob.

const [pinnedJobs, setPinnedJobs] = useState<PinnedJob[]>([
  {
    id: 'job-1',
    appName: 'MyApp',
    jobName: 'Data Export',
    progress: 42,
    appColor: '#38bdf8',
  },
]);

const handleUnpin = (jobId: string) => {
  setPinnedJobs((prev) => prev.filter((j) => j.id !== jobId));
};

<DNANavigation
  // ...
  pinnedJobs={pinnedJobs}
  onUnpinJob={handleUnpin}
/>

Build Process

The package is built with tsc (TypeScript compiler) with no bundler. The build output is plain ESM JavaScript with .d.ts declaration files.

# Install dependencies
npm install

# One-time build (also runs automatically before npm publish via prepublishOnly)
npm run build

# Watch mode during development
npm run dev

# Delete build output
npm run clean

The build script is:

"build": "tsc && cp src/styles.css dist/styles.css"

tsc compiles src/ to dist/ per tsconfig.json. The CSS file is not processed by TypeScript, so it is copied separately as a second step. The dist/ and assets/ directories are the only directories published to npm (see "files" in package.json).

Publishing a new version

  1. Increment the "version" field in package.json.
  2. Run npm publish — prepublishOnly triggers npm run build automatically.

Styles

The stylesheet (src/styles.css) uses plain global CSS class names with a dna- or app- prefix to avoid collisions. There are no CSS modules or scoped styles. The component requires DM Sans for body text and JetBrains Mono for the logo text, avatar initials, and progress ring values. Load these fonts in your app's root layout.

// next/font example (Next.js 13+)
import { DM_Sans, JetBrains_Mono } from 'next/font/google';

const dmSans = DM_Sans({ subsets: ['latin'] });
const jetbrainsMono = JetBrains_Mono({ subsets: ['latin'] });

Logo

The DNA logo defaults to a CloudFront CDN URL:

https://dscoblw2zo8x9.cloudfront.net/assets/1770003640504-w0rs6vl-DNA_LOGO.png

This URL is hardcoded in DNAHeader and works across all microsites without any local asset. To override it:

<DNANavigation
  logoSrc="/your-custom-logo.png"
  // ...other props
/>

Changelog

1.0.12

  • Added Clay to default nav items (15 apps). Link reads NEXT_PUBLIC_DNA_CLAY_URL, falling back to /clay. Highlight name is Clay. appKey is clay. App color --app-clay #d4a373 (@glamcor/dna-ui 0.3.3).

1.0.11

  • Removed CRUSH from the nav. CRUSH is not a DNA product (decision on 2026-10-26).
  • The app color table now matches the approved colors in The DNA UI Book §6.2.

1.0.10

  • Added Formic to default nav items (15 apps). Link reads NEXT_PUBLIC_DNA_FORMIC_URL, falling back to /formic. Highlight name is Formic. appKey is formic.

1.0.8

  • Added Phosphor and Sulfur to default nav items (14 apps)

1.0.7

  • Avatar image support in the header menu

1.0.3

  • Added Heat to default nav items

1.0.2

  • Updated nav items: SPOT, Nitrogen, Water, Methane, Hydrogen, Oxygen, Ammonia, Carbon, Lightning, CRUSH
  • Logo now defaults to CloudFront CDN URL
  • Fixed installation instructions for npm

1.0.1

  • Initial npm publish