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

@config-driven-testimonials/editor

v1.2.0

Published

Visual config builder for config-driven-testimonials — import, edit, export JSON

Readme

@config-driven-testimonials/editor

Visual config builder for config-driven-testimonials. Fill in your testimonials, upload avatars, tweak the theme — then export a single JSON file and drop it into your app.

  • No backend required — everything happens in the browser
  • Avatar upload built-in — center-crops and encodes to base64 automatically
  • Import / export JSON — with full Zod validation and per-field error messages
  • Drag & drop reordering — native HTML5, no extra dependencies
  • Live preview — see exactly what the widget will look like as you type, including all display variants
  • Accessible — keyboard-navigable, ARIA-labelled controls, WCAG 2.2 Level AAA compliant

npm license WCAG 2.2 AAA Lighthouse


Try it without installing

✏ Open the hosted editor


Install

npm install @config-driven-testimonials/editor
# or
pnpm add @config-driven-testimonials/editor

React 18+ is a peer dependency.


Quick start

The editor is designed for a split-screen layout: editor on the left, live TestimonialsWidget preview on the right.

import { useState } from 'react';
import { TestimonialsEditor, Toolbar, ExportPanel, ImportPanel } from '@config-driven-testimonials/editor';
import { TestimonialsWidget, parseConfig, type TestimonialConfig } from 'config-driven-testimonials';
import configJson from './testimonials.config.json';

export function EditorPage() {
  const [config, setConfig] = useState<TestimonialConfig>(parseConfig(configJson));
  const [activePanel, setActivePanel] = useState<string | null>(null);
  const [activeId, setActiveId] = useState<string | null>(null);

  return (
    <div style={{ display: 'flex', height: '100vh' }}>
      <div style={{ width: '50%', overflowY: 'auto' }}>
        <Toolbar
          activePanel={activePanel}
          onPanelChange={setActivePanel}
          exportPanel={<ExportPanel config={config} />}
          importPanel={<ImportPanel onApply={setConfig} />}
          onClearRequest={() => setConfig(parseConfig({ author: {}, testimonials: [], theme: { variant: 'cards' } }))}
          backHref="/"
        />
        <TestimonialsEditor
          value={config}
          onChange={setConfig}
          onRecommendationOpen={setActiveId}
        />
      </div>
      <div style={{ width: '50%', overflowY: 'auto' }}>
        <TestimonialsWidget config={config} activeTestimonialId={activeId ?? undefined} />
      </div>
    </div>
  );
}

API

TestimonialsEditor

The main form component. Renders sections for author profile, testimonials list, and theme settings.

| Prop | Type | Default | Description | |---|---|---|---| | value | TestimonialConfig | required | Current config state | | onChange | (config) => void | required | Called on every field change | | showValidation | boolean | false | Highlights cards green/red based on validity | | onRecommendationOpen | (id: string \| null) => void | — | Fired when a card is expanded | | onAuthorFocus | () => void | — | Fired when any author field is focused |

Toolbar

Fixed top bar with Import, Export, and Clear actions.

| Prop | Type | Description | |---|---|---| | activePanel | string \| null | Controls which panel is open | | onPanelChange | (id: string \| null) => void | Panel open/close handler | | exportPanel | ReactNode | Slot — pass <ExportPanel config={config} /> | | importPanel | ReactNode | Slot — pass <ImportPanel onApply={fn} /> | | onClearRequest | () => void | Called when user confirms "Clear all" | | backHref | string | URL for the back navigation link |

ExportPanel

Downloads the current config as a .json file.

<ExportPanel config={config} />

ImportPanel

Accepts a .json file (click or drag & drop), validates with Zod, calls onApply with the parsed config.

<ImportPanel onApply={(config) => setConfig(config)} />

ConfirmModal

Generic confirmation dialog used internally by the Toolbar. Export it if you need it elsewhere.

<ConfirmModal
  title="Clear all data?"
  description="This will remove all testimonials and reset the config."
  confirmLabel="Clear"
  onConfirm={handleClear}
  onCancel={handleCancel}
/>

Related