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

editable-content-lib

v0.1.2

Published

Make your Next.js or Vite site editable by simply adding IDs to elements. This library automatically detects elements with IDs, replaces their content with values from a content.json file, and provides an admin interface for editing content that creates G

Downloads

24

Readme

Editable Content Library

Make your Next.js or Vite site editable by simply adding IDs to elements. This library automatically detects elements with IDs, replaces their content with values from a content.json file, and provides an admin interface for editing content that creates GitHub pull requests.

Features

  • 🎯 Zero Configuration: Just add IDs to your elements
  • ✏️ Inline Editing: Double-click elements to edit in admin mode
  • 🔒 Password Protection: Secure admin access
  • 📝 Content Management: Visual admin panel for managing all content
  • 🚀 GitHub Integration: Automatic pull requests for content changes
  • 🎨 Type Support: Text, HTML, and Markdown content types
  • Validation: Content validation rules and sanitization
  • 🔄 Real-time Sync: Automatic content synchronization

Installation

```bash npm install editable-content-lib ```

Quick Start

1. Add IDs to your elements

```jsx export default function Home() { return ( Welcome to my site This is the intro text. Get Started Today Build amazing things with our platform. ) } ```

2. Initialize the library

```javascript import EditableContent from 'editable-content-lib'

const editor = new EditableContent({ contentPath: '/content.json', adminPassword: 'your-admin-password', // GitHub configuration should be done server-side for security // See secure implementation examples below })

// Initialize when DOM is ready editor.initialize() ```

3. Create content.json

```json { "homepage-title": { "value": "Welcome to my amazing site", "type": "text", "lastModified": "2024-01-15T10:30:00Z" }, "homepage-paragraph": { "value": "This is the updated intro text with more details.", "type": "text", "lastModified": "2024-01-15T10:30:00Z" }, "hero-heading": { "value": "Start Building Today", "type": "text", "lastModified": "2024-01-15T10:30:00Z" } } ```

4. Enter Admin Mode

Click the floating edit button (✏️) in the bottom right, enter your password, and start editing!

Configuration Options

```typescript interface EditableConfig { contentPath?: string // Path to content.json (default: '/content.json') adminMode?: boolean // Start in admin mode (default: false) adminPassword?: string // Password for admin access githubToken?: string // GitHub personal access token (server-side only!) githubOwner?: string // GitHub username/organization githubRepo?: string // GitHub repository name } ```

Security Considerations

⚠️ Important Security Notice: Never expose GitHub tokens or other sensitive credentials to the client-side code. Always use server-side configuration for GitHub integration.

❌ Insecure (Don't do this):

```javascript // DON'T: This exposes your GitHub token to the browser const editor = new EditableContent({ githubToken: process.env.NEXT_PUBLIC_GITHUB_TOKEN, // ❌ Exposed to client }) ```

✅ Secure (Do this instead):

```javascript // ✅ Configure GitHub server-side via API routes or server actions const editor = new EditableContent({ adminPassword: process.env.NEXT_PUBLIC_ADMIN_PASSWORD, // Only admin password can be public })

// Configure GitHub integration securely when needed if (editor.isAdminMode()) { const response = await fetch('/api/github-config') const config = await response.json() editor.configureGitHub(config) } ```

Advanced Usage

Content Types

Support for different content types:

```html

Validation Rules

Add validation to your content:

```html ```

Manual Content Updates

```javascript // Update content programmatically editor.updateContent('homepage-title', 'New title content')

// Save changes const result = await editor.saveChanges('Updated homepage content') if (result.success) { console.log('Pull request created:', result.pullRequestUrl) }

// Check for unsaved changes if (editor.hasUnsavedChanges()) { console.log('You have unsaved changes') } ```

Next.js Integration

Secure App Router Implementation

```typescript // app/layout.tsx - Secure implementation 'use client' import { useEffect } from 'react' import EditableContent from 'editable-content-lib'

let editor: EditableContent | null = null

export default function RootLayout({ children, }: { children: React.ReactNode }) { useEffect(() => { if (!editor) { editor = new EditableContent({ contentPath: '/content.json', adminPassword: process.env.NEXT_PUBLIC_ADMIN_PASSWORD, // GitHub config will be loaded securely when needed })

  editor.initialize().then(async () => {
    // Configure GitHub integration securely via API route
    if (editor?.isAdminMode()) {
      try {
        const response = await fetch('/api/github-config', {
          headers: {
            'x-admin-password': process.env.NEXT_PUBLIC_ADMIN_PASSWORD || ''
          }
        })
        if (response.ok) {
          const config = await response.json()
          editor.configureGitHub(config)
        }
      } catch (error) {
        console.warn('Failed to configure GitHub integration:', error)
      }
    }
  })
}

}, [])

return ( {children} ) } ```

Secure API Route for GitHub Configuration

```typescript // app/api/github-config/route.ts import { NextRequest, NextResponse } from 'next/server'

export async function GET(request: NextRequest) { try { // Verify admin authentication const adminPassword = request.headers.get('x-admin-password') if (adminPassword !== process.env.ADMIN_PASSWORD) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) }

// Return GitHub configuration from server environment
const githubConfig = {
  token: process.env.GITHUB_TOKEN,
  owner: process.env.GITHUB_OWNER,
  repo: process.env.GITHUB_REPO,
}

if (!githubConfig.token || !githubConfig.owner || !githubConfig.repo) {
  return NextResponse.json({ error: 'GitHub configuration incomplete' }, { status: 500 })
}

return NextResponse.json(githubConfig)

} catch (error) { return NextResponse.json({ error: 'Internal server error' }, { status: 500 }) } } ```

Server Actions Alternative

```typescript // app/actions/github-actions.ts 'use server'

import { GitHubClient } from 'editable-content-lib'

export async function saveContentToGitHub(content: any, commitMessage?: string) { try { const githubClient = new GitHubClient({ token: process.env.GITHUB_TOKEN!, owner: process.env.GITHUB_OWNER!, repo: process.env.GITHUB_REPO!, })

const result = await githubClient.createContentPullRequest(content, commitMessage)
return { success: true, pullRequestUrl: result.pullRequestUrl }

} catch (error: any) { return { success: false, error: error.message } } } ```

Vite Integration

```typescript // main.ts - Secure Vite implementation import EditableContent from 'editable-content-lib'

const editor = new EditableContent({ contentPath: '/content.json', adminPassword: import.meta.env.VITE_ADMIN_PASSWORD, // GitHub configuration should be handled server-side })

document.addEventListener('DOMContentLoaded', () => { editor.initialize() }) ```

Environment Variables

Server-Side Environment Variables (Secure)

Create a .env.local file for server-side variables:

```bash

Server-side only (secure)

ADMIN_PASSWORD=your-secure-password GITHUB_TOKEN=ghp_your-github-token GITHUB_OWNER=your-username GITHUB_REPO=your-repo-name ```

Client-Side Environment Variables (Limited)

Only expose non-sensitive variables to the client:

```bash

Next.js - Client-side (only non-sensitive data)

NEXT_PUBLIC_ADMIN_PASSWORD=your-secure-password

Vite - Client-side (only non-sensitive data)

VITE_ADMIN_PASSWORD=your-secure-password ```

GitHub Setup

  1. Create a GitHub Personal Access Token:

    • Go to GitHub Settings > Developer settings > Personal access tokens
    • Generate a new token with repo permissions
    • Store the token in your server-side environment variables (never client-side)
  2. Repository Setup:

    • Ensure your repository has a public/content.json file (or your configured path)
    • The library will automatically create pull requests when content is saved
  3. Security Best Practices:

    • Never expose GitHub tokens to the client-side
    • Use server-side API routes or server actions for GitHub operations
    • Implement proper authentication for admin access

API Reference

EditableContent Class

Methods

  • initialize(): Initialize the library and scan for editable elements
  • enableAdminMode(password?): Enable admin mode with optional password
  • disableAdminMode(): Disable admin mode
  • isAdminMode(): Check if admin mode is active
  • updateContent(id, content): Update content for a specific element
  • saveChanges(commitMessage?): Save all changes (creates GitHub PR if configured)
  • configureGitHub(config): Configure GitHub integration (use server-side)
  • hasGitHubIntegration(): Check if GitHub is configured
  • validateGitHubConnection(): Validate GitHub connection
  • getRecentPullRequests(): Get recent content pull requests
  • hasUnsavedChanges(): Check for unsaved changes
  • destroy(): Clean up and remove event listeners

Troubleshooting

Common Security Issues

  1. GitHub Token Exposed: If you see warnings about exposed tokens, move GitHub configuration to server-side API routes
  2. CORS Issues: Ensure your API routes are properly configured for your domain
  3. Authentication Failures: Verify that admin passwords match between client and server

Performance Tips

  1. Content Caching: The library automatically caches content to reduce API calls
  2. Lazy Loading: GitHub integration is only loaded when admin mode is enabled
  3. Debounced Saves: Content changes are debounced to prevent excessive API calls

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE file for details.