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

@particulatesolutions/cms-editor

v0.1.5

Published

CMS editor components for Socialfunders platform (internal use)

Readme

@particulatesolutions/cms-editor

⚠️ Internal Package: This package contains CMS editor components for the Socialfunders platform. While publicly available on npm, it's not designed for external use and requires Socialfunders backend infrastructure.

Installation

npm install @particulatesolutions/cms-editor

Internationalization (i18n)

This library includes vue-i18n and provides default translations in German and English. You must set up vue-i18n in your application for the components to display translated text.

Setting up i18n

  1. Import and set up vue-i18n with the library's default translations:
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
import { defaultTranslations } from '@particulatesolutions/cms-editor'

const i18n = createI18n({
  legacy: false,
  locale: 'de', // or 'en'
  fallbackLocale: 'de',
  messages: {
    de: {
      ...defaultTranslations.de,
      // Add your other German translations here
    },
    en: {
      ...defaultTranslations.en,
      // Add your other English translations here
    }
  }
})

app.use(i18n)
  1. Switching languages dynamically:
import { useI18n } from 'vue-i18n'

const { locale } = useI18n()

// Switch to English
locale.value = 'en'

// Switch to German
locale.value = 'de'

Overriding Translations

You can override any library translation by providing your own values:

const i18n = createI18n({
  locale: 'en',
  messages: {
    en: {
      ...defaultTranslations.en,
      // Override specific library translations
      general: {
        save: 'Save Changes', // Override 'Save' with 'Save Changes'
        unnamed: 'Untitled Item' // Override 'Unnamed' with 'Untitled Item'
      },
      // Override other sections as needed
      contentBlockEdit: {
        title: 'Main Heading'
      }
    }
  }
})

Available Translation Keys

The library provides translations in German (de) and English (en) organized into the following sections:

  • general: Common labels (save, unnamed, dash)
  • componentPalette: Component palette labels
  • contentBlock: Content block labels
  • contentBlockEdit: Content block editing form labels
  • buttonTable: Button table labels
  • metadataPanel: SEO metadata form labels
  • projectExplore: Project explore dialog labels

Refer to the defaultTranslations export for the complete list of available keys and their values.

Usage

import {
  CMSContentArea,
  CMSComponentPalette,
  CMSMetadataPanel,
  type ContentBlock,
  type ComponentType
} from '@particulatesolutions/cms-editor'

Example

<script setup lang="ts">
import { ref } from 'vue'
import {
  CMSContentArea,
  CMSComponentPalette,
  type ContentBlock,
  type ComponentType
} from '@particulatesolutions/cms-editor'

// Define your component types (typically loaded from API)
const componentTypes = ref<ComponentType[]>([
  { id: '1', name: 'Text Block', type: 'text', icon: 'fa-align-left' },
  { id: '2', name: 'Image Block', type: 'image', icon: 'fa-image' },
  { id: '3', name: 'Projects', type: 'projects', icon: 'fa-list' },
])

// Define your content blocks
const contentBlocks = ref<ContentBlock[]>([
  {
    id: 'block-1',
    name: 'Welcome Section',
    componentType: 'text',
    order: 0,
    settings: {
      title: 'Welcome',
      text: 'This is a sample block',
      positioning: 'image-left',
      theme: 'light',
    },
  },
])

// Handle events emitted by components
function handleAddBlock(block: ContentBlock, index: number) {
  contentBlocks.value.splice(index, 0, block)
}

function handleRemoveBlock(blockId: string) {
  const index = contentBlocks.value.findIndex(b => b.id === blockId)
  if (index !== -1) {
    contentBlocks.value.splice(index, 1)
  }
}

function handleReorder(fromIndex: number, toIndex: number) {
  const [removed] = contentBlocks.value.splice(fromIndex, 1)
  contentBlocks.value.splice(toIndex, 0, removed)
}

function handleSaveBlock(blockId: string, formData: any) {
  const block = contentBlocks.value.find(b => b.id === blockId)
  if (block) {
    Object.assign(block.settings, formData)
  }
}
</script>

<template>
  <div class="cms-editor">
    <aside>
      <CMSComponentPalette :components="componentTypes" />
    </aside>
    <main>
      <CMSContentArea
        :blocks="contentBlocks"
        :components="componentTypes"
        @add:block="handleAddBlock"
        @remove:block="handleRemoveBlock"
        @reorder="handleReorder"
        @save:block="handleSaveBlock"
      />
    </main>
  </div>
</template>

Component Architecture

The library follows a props/events pattern:

  • Components accept data via props
  • Components communicate changes via emitted events
  • Parent application handles all state management and data persistence
  • No internal state management library required

This design provides maximum flexibility and allows the parent application to integrate with any backend or state management solution.

TypeScript Types

The library exports comprehensive TypeScript types for type-safe development:

  • ContentBlock - Base interface for all content blocks (union type)
  • GenericContentBlock - Standard content blocks with ContentBlockSettings
  • ProjectContentBlock - Project listing blocks with ProjectSettings
  • ContentBlockSettings - Settings for generic blocks (title, text, imageUrl, positioning, theme, buttons, etc.)
  • ProjectSettings - Settings for project listing blocks (filters, sorting, display options)
  • ContentBlockFormValues - Form data structure for editing generic blocks
  • ContentBlockButton - Button configuration with icon, text, URL, type, and ariaLabel
  • ComponentType - Available component types with id, name, type, and icon
  • ContentBlockPosition - 'text-left' | 'image-left' | 'text-top' | 'image-top'
  • ContentBlockTheme - 'light' | 'dark'

Components

CMSButtonTable

Manage buttons within content blocks with drag-and-drop reordering.

Props:

  • buttons: ContentBlockButton[] - Array of button objects

Emits:

  • update:buttons - When buttons are modified

CMSComponentPalette

Drag-and-drop palette displaying available block types that can be dragged to the content area.

Props:

  • components: ComponentType[] - Array of available component types

CMSContentArea

Main canvas for composing pages. Handles drag-and-drop from the palette and reordering of existing blocks.

Props:

  • blocks: ContentBlock[] - Array of content blocks
  • components: ComponentType[] - Array of available component types
  • visible?: boolean - Controls visibility of edit dialogs

Emits:

  • add:block(block: ContentBlock, index: number) - When a block is added from palette
  • remove:block(blockId: string) - When a block is removed
  • after:toggle-visibility(blockId: string, visibilityBefore: boolean, visibilityAfter: boolean) - When block visibility is toggled
  • reorder(fromIndex: number, toIndex: number) - When blocks are reordered
  • save:block(blockId: string, formData: ContentBlockFormValues) - When block settings are saved
  • save:project-settings(blockId: string, settings: ProjectSettings) - When project block settings are saved

CMSContentBlock

Individual block renderer with edit, remove, and visibility toggle controls.

Props:

  • block: ContentBlock - The content block to render
  • blockTypeName: string - Display name of the block type

Emits:

  • edit - When edit button is clicked
  • remove - When remove button is clicked
  • toggle-visibility - When visibility toggle is clicked

CMSContentBlockEditDialog

Dialog for editing generic content block settings.

Props:

  • content-block: ContentBlock - The block being edited
  • visible: boolean - Controls dialog visibility

Emits:

  • update:visible - When dialog visibility changes
  • save:block(blockId: string, formData: ContentBlockFormValues) - When form is submitted

CMSMetadataPanel

SEO metadata form for managing title, description, and Open Graph tags.

Props:

  • modelValue: any - Current metadata object

Emits:

  • update:modelValue - When metadata is updated

CMSProjectExploreDialog

Dialog for configuring project listing blocks with filters, sorting, and display options.

Props:

  • content-block: ContentBlock - The project block being edited
  • visible: boolean - Controls dialog visibility

Emits:

  • update:visible - When dialog visibility changes
  • save:project-settings(blockId: string, settings: ProjectSettings) - When settings are saved

Requirements

Peer Dependencies

  • Vue 3.5+
  • PrimeVue 4.5+
  • @primevue/themes 4.5+
  • @primevue/forms 4.5+
  • @primeuix/themes 2.0+
  • @primeuix/styled (latest)
  • @vueuse/integrations 14.0+
  • zod 4.2+
  • sortablejs 1.15+

Bundled Dependencies

  • vue-i18n 11.0+
  • tailwindcss 4.1+ (self-contained, no setup required)
  • @tailwindcss/vite 4.1+
  • tailwindcss-primeui 0.6+

Styling

This library uses Tailwind CSS v4 for utility classes and styling. The compiled CSS bundle (dist/index.css) is fully self-contained and includes all necessary Tailwind utilities used by the components.

Parent applications do NOT need to:

  • Install Tailwind CSS
  • Configure Tailwind
  • Include Tailwind in their build process

Simply import the library's CSS:

import '@particulatesolutions/cms-editor/style.css'

The generated CSS is minimal (~2KB gzipped) and includes only the Tailwind utilities actually used by the components, plus component-specific styles.

Development

This package includes a demo app for testing and developing components visually.

# Install dependencies
npm install

# Run demo app with hot reload (http://localhost:5173)
npm run dev

# Build library for distribution
npm run build

# Watch build mode (for local development with file: protocol)
npm run build:watch

# Run unit tests
npm run test:unit

# Type checking
npm run type-check

# Lint code
npm run lint

Demo vs Library Build:

  • npm run dev - Runs the demo app (App.vue) with all components showcased
  • npm run build - Builds only the library (from src/index.ts) to dist/
  • Demo files (App.vue, main.ts) are never included in the published package
  • The library has no internal state management (Pinia) - parent app manages state

License

MIT