Search by

j87nl / laravel-vue-cms

J87.nl

Vue and Inertia admin for j87nl/laravel-cms.

Package info

github.com/J87NL/laravel-vue-cms

pkg:composer/j87nl/laravel-vue-cms

Statistics

Installs: 636

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.6.0 2026-11-03 16:15 UTC

This package is auto-updated.

Last update: 2026-11-03 16:18:38 UTC


README

Inertia and Vue admin for j87nl/laravel-cms: pages, blocks, media, menus, redirects and site settings, built on TranquilTools FormBuilder and TableBuilder.

When a published page has pending changes (proposed through the MCP draft tools of laravel-cms), the page editor shows what they change compared with the live page, block by block with a word-level diff of the text, and links to a signed preview of the page with the changes applied. See Publication.

A separate spam protection screen (admin/cms/settings/spam-protection) holds the Cloudflare Turnstile keys of the contact form. The secret key is stored encrypted and never sent back to the browser. See Spam protection.

The admin tables use compact cells (px-3 py-2, through the shared J87NL\VueCms\Tables\CmsTable). A row of the block, media, menu and redirect tables opens its edit screen on a click, or with Tab and Enter, when the user may open that screen; the separate Edit action is gone. See Security.

The Vue pages stay inside the package. The app's Inertia resolver loads them from the package, and an app overrides a single page through the configurable page names in config/vue-cms.php.

Requirements

  • PHP 8.5, Laravel 13 and Inertia 3 with Vue 3
  • j87nl/laravel-cms
  • tranquil-tools/laravel-vue-form-builder and tranquil-tools/laravel-vue-table-builder (installed as dependencies)
  • laravel-vue-i18n and a $can(permission) helper on the Vue app

Installation

composer require j87nl/laravel-vue-cms
php artisan vendor:publish --tag=vue-cms-config

The admin routes live under vue-cms.admin.prefix (default admin/cms) behind vue-cms.admin.middleware (default web and auth), and every screen checks one of the CMS permissions.

Vite and the page resolver

Add the aliases and load the package pages next to your own:

// vite.config.ts
resolve: {
    alias: {
        '@cms': fileURLToPath(new URL('./vendor/j87nl/laravel-vue-cms/resources/js', import.meta.url)),
        '@form-builder': fileURLToPath(new URL('./vendor/tranquil-tools/laravel-vue-form-builder/resources/js', import.meta.url)),
        '@table-builder': fileURLToPath(new URL('./vendor/tranquil-tools/laravel-vue-table-builder/resources/js', import.meta.url)),
    },
},
// resources/js/app.ts
const appPages = import.meta.glob<DefineComponent>('./pages/**/*.vue');
const cmsPages = import.meta.glob<DefineComponent>('@cms/pages/**/*.vue');

resolve: async (name) => {
    const page = name.startsWith('cms/')
        ? Object.entries(cmsPages).find(([path]) => path.endsWith(`/pages/${name.slice(4)}.vue`))?.[1]
        : appPages[`./pages/${name}.vue`];

    return (await page!()).default;
},

Add "@cms/*": ["./vendor/j87nl/laravel-vue-cms/resources/js/*"] to the paths in tsconfig.json, and add the package's .vue files to Tailwind's sources so their classes are generated:

@source '../../vendor/j87nl/laravel-vue-cms/resources/js/**/*.vue';

Host app contract

  • Confirm dialog: the package never uses window.confirm. Provide a promise-based confirm function from your layout: provide('confirm', (message: string) => Promise<boolean>). Without it every confirmation resolves to false, so destructive actions do nothing.
  • Breadcrumbs: pages set a breadcrumbs layout prop through setLayoutProps. Your admin layout reads it and renders the trail.
  • Translations: strings use vue-cms:: keys through laravel-vue-i18n. Make the package's lang directory available to the i18n Vite plugin, for example with a lang/vendor/vue-cms symlink to vendor/j87nl/laravel-vue-cms/lang.

Navigation and permissions

The package pushes its menu items into the config key named by vue-cms.navigation_config_key (default j87nl.navigation). Each item has a key, a translation label, a route, a Lucide icon name (FileText, Image, Menu, Signpost, Settings2), a permission and an order. The app builds its sidebar from that key.

Map the CMS permissions to your roles: cms.pages.edit, cms.pages.publish, cms.menus, cms.media, cms.redirects and cms.settings. Publishing, taking offline, planning and changing a published page all need cms.pages.publish.

Toasts

Success messages are flashed with Inertia::flash() under vue-cms.toast_flash_key (default toast) as { type, message }.

Testing

composer update
vendor/bin/pest

License

MIT