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
Create a GitHub Personal Access Token:
- Go to GitHub Settings > Developer settings > Personal access tokens
- Generate a new token with
repopermissions - Store the token in your server-side environment variables (never client-side)
Repository Setup:
- Ensure your repository has a
public/content.jsonfile (or your configured path) - The library will automatically create pull requests when content is saved
- Ensure your repository has a
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 elementsenableAdminMode(password?): Enable admin mode with optional passworddisableAdminMode(): Disable admin modeisAdminMode(): Check if admin mode is activeupdateContent(id, content): Update content for a specific elementsaveChanges(commitMessage?): Save all changes (creates GitHub PR if configured)configureGitHub(config): Configure GitHub integration (use server-side)hasGitHubIntegration(): Check if GitHub is configuredvalidateGitHubConnection(): Validate GitHub connectiongetRecentPullRequests(): Get recent content pull requestshasUnsavedChanges(): Check for unsaved changesdestroy(): Clean up and remove event listeners
Troubleshooting
Common Security Issues
- GitHub Token Exposed: If you see warnings about exposed tokens, move GitHub configuration to server-side API routes
- CORS Issues: Ensure your API routes are properly configured for your domain
- Authentication Failures: Verify that admin passwords match between client and server
Performance Tips
- Content Caching: The library automatically caches content to reduce API calls
- Lazy Loading: GitHub integration is only loaded when admin mode is enabled
- Debounced Saves: Content changes are debounced to prevent excessive API calls
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see LICENSE file for details.
