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

lf-pagebuilder-vue

v0.0.122

Published

Constructor de páginas visual basado en Vue.js que permite crear y diseñar páginas web de forma intuitiva mediante componentes arrastrables y configurables

Readme

lf-pagebuilder-vue

Editor visual para construir páginas HTML usando los componentes de libreria-astro-lefebvre.


⚡ Referencia rápida — Todas las opciones

Modo 1 — Componente Vue

npm install lf-pagebuilder-vue
<template>
  <Pagebuilder
    :isProduction="false"
    :debugMode="false"
    :submitForm="false"
    inputId="mi-input-hidden"
    :excludeComponentTypes="['SEO', 'Footer']"
    :excludeComponentTags="['boton', 'destacado']"
    :includeOnlyComponentTags="['articulo']"
    :visibleSections="['Header', 'Body', 'Footer']"
    allowRenderMode="open"
    limboToken="eyJ..."
    ateneaToken="eyJ..."
    :ledithorAiTools="['improve', 'improve-stream']"
    client:only="vue"
  />
</template>

<script setup>
import { Pagebuilder } from 'lf-pagebuilder-vue';
import 'lf-pagebuilder-vue/styles';
</script>

| Prop | Tipo | Default | Descripción | |------|------|---------|-------------| | isProduction | boolean | false | true = API producción · false = API desarrollo | | debugMode | boolean | false | Muestra panel de import/export JSON y botón de carga desde localStorage | | submitForm | boolean | false | Al guardar, busca el <form> padre y hace .submit() automáticamente | | inputId | string \| null | null | ID del <input hidden> donde se vuelca el JSON al guardar y del que se lee el estado inicial | | excludeComponentTypes | string[] | [] | Categorías de componentes que NO aparecerán en el selector. "Repetidor" siempre se excluye. | | excludeComponentTags | string[] | [] | Tags de componentes a excluir (lista negra). Un componente con cualquiera de estos tags no aparecerá. | | includeOnlyComponentTags | string[] | [] | Solo muestra componentes que tengan al menos uno de estos tags (lista blanca). La exclusión tiene prioridad. | | visibleSections | string[] | — | Secciones visibles. Si no se indica, se muestran todas. Valores: Header, Body, Footer, Sidebar | | allowRenderMode | 'open' \| 'fullpage' \| 'onlybody' | 'open' | open = el usuario elige · fullpage = forzado página completa · onlybody = forzado solo body | | limboToken | string | — | Token JWT para el gestor de imágenes Limbo. Obtenerlo server-side con fetchLimboToken() | | ateneaToken | string | — | Token JWT de Atenea para las funcionalidades de IA en el editor de texto (LedithorEditor). Obtenerlo server-side con fetchAteneaToken(). Sin este token el botón de IA no aparece. | | ledithorAiTools | string[] | — | Herramientas de IA a habilitar en el editor de texto. Solo se aplican si también se proporciona ateneaToken. Ej: ['improve', 'improve-stream'] | | viewOnly | boolean | false | Modo solo visualización: oculta toda la UI de edición (toolbar, panel de componentes). Usar para la vista pública. |

Categorías disponibles para excludeComponentTypes: Call to Action, Contenido, Separador, Texto, Cabecera, Footer, Imagen, Repetidor, Formulario, Título, SEO


Modo 2 — Script IIFE (Symfony / Twig / cualquier backend)

<link rel="stylesheet" href="/build/lf-pagebuilder-iife.css">
<script src="/build/lf-pagebuilder-iife.iife.js"></script>

<!-- EDITOR (crear) -->
<input
  type="hidden"
  class="js-lf-pagebuilder-vue-input"
  name="pagebuilder[pageConfig]"
  id="pagebuilder-new"
  value=""
  data-is-production="false"
  data-debug-mode="true"
  data-submit-form="true"
  data-allow-render-mode="open"
  data-limbo-token="eyJ..."
  data-atenea-token="eyJ..."
  data-ledithor-ai-tools='["improve","improve-stream"]'
/>

<!-- EDITOR (editar) -->
<input
  type="hidden"
  class="js-lf-pagebuilder-vue-input"
  name="pagebuilder[pageConfig]"
  id="pagebuilder-123"
  value="{JSON existente del pageConfig}"
  data-is-production="false"
  data-submit-form="true"
  data-exclude-component-types="SEO,Footer,Cabecera"
  data-limbo-token="eyJ..."
/>

<!-- VISTA PÚBLICA (solo lectura) -->
<div id="lf-pagebuilder-render"></div>
<script>
  window.LfPagebuilder.render({
    el: '#lf-pagebuilder-render',
    pageConfig: {{ pageConfig|raw }},  {# string JSON o objeto #}
    isProduction: true
  });
</script>

| Atributo data-* | Valores | Default | Descripción | |-------------------|---------|---------|-------------| | data-is-production | "true" | "false" | "false" | Entorno de la API de renderizado | | data-debug-mode | "true" | "false" | "false" | Muestra panel de import/export JSON y botón de carga desde localStorage | | data-submit-form | "true" | "false" | "false" | Al guardar, busca el <form> padre y hace .submit() automáticamente | | data-exclude-component-types | string (comas) | — | Categorías de componentes a excluir. Ej: "SEO,Footer,Cabecera" | | data-exclude-component-tags | string (comas) | — | Tags de componentes a excluir (lista negra). Ej: "boton,destacado" | | data-include-only-component-tags | string (comas) | — | Solo muestra componentes con estos tags (lista blanca). La exclusión tiene prioridad. | | data-visible-sections | string (comas) | — | Secciones visibles. Ej: "Header,Body" | | data-allow-render-mode | "open" | "fullpage" | "onlybody" | "open" | Controla el modo de renderizado | | data-limbo-token | string | — | Token JWT de Limbo para el gestor de imágenes | | data-atenea-token | string | — | Token JWT de Atenea para las funcionalidades de IA. Sin este token el botón de IA no aparece. | | data-ledithor-ai-tools | string (JSON array) | — | Herramientas de IA a habilitar. Solo se aplican si hay data-atenea-token. Ej: '["improve","improve-stream"]' |

El id del input se usa como clave de localStorage y como referencia interna. Si no tiene id, se genera uno automáticamente.

Compatibilidad de atributos: El componente acepta también los tokens como atributos planos (sin prefijo data-): limboToken="...", ateneaToken="...", ledithorAiTools='[...]'. La forma recomendada es siempre data-*.


API global window.LfPagebuilder

| Método | Descripción | |--------|-------------| | LfPagebuilder.init(config?) | Inicializa el editor en todos los elementos .js-lf-pagebuilder-vue-input de la página | | LfPagebuilder.render({ el, pageConfig, isProduction? }) | Renderiza la página en modo solo visualización (sin UI de edición) | | LfPagebuilder.destroyAll() | Destruye todas las instancias activas | | LfPagebuilder.getInstances() | Devuelve todas las instancias activas | | LfPagebuilder.setComponents(components) | Reemplaza la lista de componentes disponibles | | LfPagebuilder.addComponent(component) | Añade un componente a la lista disponible |

El IIFE se auto-inicializa en DOMContentLoaded si hay elementos con el selector .js-lf-pagebuilder-vue-input en el DOM. No es necesario llamar a init() manualmente.


Integración con Symfony/Twig — Contrato completo

Cómo funciona el intercambio de datos con el formulario

El componente actúa como un "enhanced textarea":

  1. Lee su valor inicial de input.value — en onMounted, el editor lee el JSON del value del input y lo carga como estado inicial del canvas. Si está vacío, el editor empieza en blanco (modo crear). Si contiene JSON, lo inicializa con esa configuración (modo editar).

  2. Escribe en input.value al guardar — cuando el usuario pulsa "Guardar" dentro del editor, el JSON actualizado se escribe en input.value.

  3. Envía el formulario si data-submit-form="true" — después de escribir en input.value, busca el <form> padre y llama a .submit(). Esto permite que Symfony valide y persista el pageConfig.

{# Crear #}
<form method="post" action="{{ path('landing_create') }}">
  <input type="hidden"
         id="pagebuilder-new"
         name="pagebuilder[pageConfig]"
         class="js-lf-pagebuilder-vue-input"
         value=""
         data-is-production="{{ app.environment == 'prod' ? 'true' : 'false' }}"
         data-submit-form="true"
         data-limbo-token="{{ limboToken }}"
         data-atenea-token="{{ ateneaToken }}"
         data-ledithor-ai-tools='["improve","improve-stream"]'
  />
  {# El CSRF token y otros campos del formulario van aquí #}
</form>

{# Editar #}
<form method="post" action="{{ path('landing_edit', {id: landing.id}) }}">
  <input type="hidden"
         id="pagebuilder-{{ landing.id }}"
         name="pagebuilder[pageConfig]"
         class="js-lf-pagebuilder-vue-input"
         value="{{ landing.pageConfig|json_encode }}"
         data-is-production="{{ app.environment == 'prod' ? 'true' : 'false' }}"
         data-submit-form="true"
         data-exclude-component-types="SEO,Footer,Cabecera"
         data-limbo-token="{{ limboToken }}"
  />
</form>

{# Vista pública #}
<div id="lf-pagebuilder-render"></div>
<script>
  window.LfPagebuilder.render({
    el: '#lf-pagebuilder-render',
    pageConfig: {{ landing.pageConfig|raw }},
    isProduction: {{ app.environment == 'prod' ? 'true' : 'false' }}
  });
</script>

Instalación

npm i lf-pagebuilder-vue

Luego en tu package.json, cambia la versión a latest para tener siempre la última:

{
  "dependencies": {
    "lf-pagebuilder-vue": "latest"
  }
}

¿Qué es?

El Pagebuilder permite al usuario arrastrar y configurar componentes de la librería de componentes Astro de Lefebvre para diseñar páginas de forma visual.

El Pagebuilder NO renderiza la página final. Genera un JSON de configuración que se envía a una API externa renderizadora, que es la encargada de generar el HTML final.


Integración con Limbo (gestión de imágenes)

Si se quiere usar el sistema de imágenes Limbo desde el Pagebuilder:

Variables de entorno (.env):

PUBLIC_LIMBO_PUBLIC_KEY=pk_tu_public_key
IS_PROD=FALSE

Obtener token server-side y pasarlo al componente:

---
import { Pagebuilder } from 'lf-pagebuilder-vue';
import { fetchLimboToken } from 'lf-pagebuilder-vue/limbo';

let limboToken = '';
try {
  const result = await fetchLimboToken({
    publicKey: import.meta.env.PUBLIC_LIMBO_PUBLIC_KEY || '',
    isProduction: import.meta.env.IS_PROD === 'TRUE'
  });
  limboToken = result.token;
} catch (e) {
  console.error('[Pagebuilder] Error obteniendo token de Limbo:', e);
}
---

<Pagebuilder
  limboToken={limboToken}
  isProduction={import.meta.env.IS_PROD === 'TRUE'}
  inputId="mi-input"
  client:only="vue"
/>

El token se obtiene en el frontmatter (server-side), evitando exponer la Public Key al cliente.

fetchLimboToken — opciones

import { fetchLimboToken } from 'lf-pagebuilder-vue/limbo';

const { token, expires_in } = await fetchLimboToken({
  publicKey: 'pk_xxx',       // requerido
  isProduction: false,        // opcional, default: false
  limboApiUrl: 'https://...' // opcional, sobreescribe isProduction
});

Integración con Atenea (IA en el editor de texto)

Si se quiere usar las funcionalidades de IA de LedithorEditor (botón "Improve", etc.):

Variables de entorno (.env):

ATENEA_USERNAME=ledithor
ATENEA_APIKEY=tu_apikey_aqui
IS_PROD=FALSE

Obtener token server-side y pasarlo al componente:

---
import { Pagebuilder } from 'lf-pagebuilder-vue';
import { fetchAteneaToken } from 'lf-pagebuilder-vue/atenea';

let ateneaToken = '';
try {
  const result = await fetchAteneaToken({
    username: import.meta.env.ATENEA_USERNAME || '',
    apiKey:   import.meta.env.ATENEA_APIKEY || '',
    isProduction: import.meta.env.IS_PROD === 'TRUE'
  });
  ateneaToken = result.token;
} catch (e) {
  console.error('[Pagebuilder] Error obteniendo token de Atenea:', e);
}
---

<Pagebuilder
  ateneaToken={ateneaToken}
  :ledithorAiTools="['improve', 'improve-stream']"
  client:only="vue"
/>

Si ateneaToken no se proporciona (o está vacío), el botón de IA no aparece en el editor de texto. ledithorAiTools solo tiene efecto si hay token.

fetchAteneaToken — opciones

import { fetchAteneaToken } from 'lf-pagebuilder-vue/atenea';

const { token, expiresAt } = await fetchAteneaToken({
  username: 'ledithor',       // requerido
  apiKey: 'tu_apikey',        // requerido
  isProduction: false,         // opcional, default: false
  ateneaApiUrl: 'https://...' // opcional, sobreescribe isProduction
});
// expiresAt: Unix timestamp (segundos) del claim `exp` del JWT

| Parámetro | Tipo | Default | Descripción | |-----------|------|---------|-------------| | username | string | — | Usuario de Atenea | | apiKey | string | — | API Key del usuario | | isProduction | boolean | false | truehttps://atenea.lefebvre.es · false → URL de desarrollo | | ateneaApiUrl | string | — | URL base personalizada (sobreescribe isProduction) |


Funcionalidades del editor

Color de fondo en filas y columnas

Cada fila y cada columna del editor puede tener un color de fondo personalizado con soporte de canal alpha (opacidad). El color se configura desde el panel de configuración de la fila o columna y se exporta junto al resto de la configuración del layout.

El color se almacena en el JSON de configuración como un valor rgba(r, g, b, a) dentro de la propiedad backgroundColor:

{
  "rows": [
    {
      "config": {
        "backgroundColor": "rgba(255, 200, 100, 0.75)"
      },
      "columns": [
        {
          "config": {
            "backgroundColor": "rgba(240, 240, 240, 1)"
          },
          "components": []
        }
      ]
    }
  ]
}

Resaltado de elemento en edición

Cuando se abre el panel de configuración de una fila, columna o componente, el elemento correspondiente se resalta visualmente con un borde ámbar y un halo de sombra. El resaltado desaparece al cerrar el panel.


Build

El proyecto tiene dos builds:

Build estándar (librería npm)

npm run build

Genera en dist/:

  • index.js — ES Module
  • index.cjs — CommonJS
  • index.d.ts — Tipos TypeScript
  • limbo.js / limbo.cjs — Utilidades de Limbo (server-side)
  • atenea.js / atenea.cjs — Utilidades de Atenea (server-side)
  • styles.css — Estilos

Build Symfony (IIFE)

npm run build:symfony

Genera en dist-symfony/:

  • lf-pagebuilder-iife.iife.js — Script autocontenido (incluye Vue y todas las dependencias)
  • lf-pagebuilder-iife.css — Estilos con utilidades Tailwind prefijadas (mecano:)

Build completo

npm run build:all

Ejecuta ambos builds.


⚠️ Desarrollo local

IMPORTANTE: Lee esta sección completa antes de trabajar con este proyecto localmente.

Trabajar con npm link

Para probar cambios localmente en otro proyecto sin publicar:

# 1. En lf-pagebuilder-vue
cd /ruta/a/lf-pagebuilder-vue
npm link

# 2. En tu proyecto consumidor
cd /ruta/a/tu-proyecto
npm link lf-pagebuilder-vue

⚠️ CRÍTICO: Múltiples librerías con npm link

Este proyecto depende de libreria-astro-lefebvre. Si necesitas trabajar con ambas librerías localmente:

# ❌ INCORRECTO - El segundo comando ROMPE el primero
npm link lf-pagebuilder-vue
npm link libreria-astro-lefebvre

# ✅ CORRECTO - Linkear TODAS en UN SOLO comando
npm link lf-pagebuilder-vue libreria-astro-lefebvre

Flujo completo para trabajar con ambas librerías

# 1. En lf-pagebuilder-vue
cd /ruta/a/lf-pagebuilder-vue
npm link

# 2. En libreria-astro-lefebvre
cd /ruta/a/libreria-astro-lefebvre
npm link

# 3. En tu proyecto consumidor — AMBAS EN UN SOLO COMANDO
cd /ruta/a/tu-proyecto
npm link lf-pagebuilder-vue libreria-astro-lefebvre

Deshacer los enlaces

cd /ruta/a/tu-proyecto
npm unlink lf-pagebuilder-vue libreria-astro-lefebvre
npm install

Watch mode

npm run dev

Ejecuta vite build --watch y recompila automáticamente cuando hay cambios.


📘 Publicar en npm

Para publicar una nueva versión:

  1. Subir la versión en package.json
  2. Compilar y publicar:
    npm run build:all
    npm publish --access public

Configurar acceso a npm (primera vez)

  1. Solicitar acceso al equipo desarrollowebteamlef en npm
  2. Crear un token de acceso en tu perfil de npm → Access Tokens
  3. Añadir el token en ~/.npmrc:
    //registry.npmjs.org/:_authToken=TU_TOKEN_AQUI

Instalación y dependencias

Dependencias requeridas en el proyecto padre

npm install lf-pagebuilder-vue@latest vue@^3.3.0 vuedraggable@^4.1.0

Configuración en proyectos Astro

npm install @astrojs/vue tailwindcss @tailwindcss/vite

En astro.config.mjs:

import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
  integrations: [vue()],
  vite: {
    plugins: [tailwindcss()],
    ssr: {
      noExternal: ['libreria-astro-lefebvre', 'lf-pagebuilder-vue'],
    },
  },
});