webx-ui / site
A Laravel application with the WebX UI admin panel on it, ready for the modules the site needs.
Requires
- php: ^8.4
- laravel/framework: ^13.17
- laravel/tinker: ^3.0
- webx-ui/module-admin: ^0.75.0
- webx-ui/module-auth: ^0.75.0
Requires (Dev)
- fakerphp/faker: ^1.23
- laravel/pail: ^1.2.5
- laravel/pint: ^1.27
- mockery/mockery: ^1.6
- nunomaduro/collision: ^8.6
- phpunit/phpunit: ^12.5.12
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v0.75.0
- v0.74.0
- v0.73.0
- v0.72.0
- v0.71.0
- v0.70.0
- v0.69.0
- v0.68.0
- v0.67.0
- v0.66.0
- v0.65.0
- v0.64.0
- v0.63.0
- v0.62.1
- v0.62.0
- v0.61.1
- v0.61.0
- v0.60.0
- v0.59.0
- v0.58.0
- v0.57.0
- v0.56.0
- v0.55.0
- v0.54.0
- v0.53.1
- v0.53.0
- v0.52.0
- v0.51.0
- v0.50.0
- v0.49.2
- v0.49.1
- v0.49.0
- v0.48.0
- v0.47.0
- v0.46.0
- v0.45.0
- v0.44.1
- v0.44.0
- v0.43.0
- v0.42.3
- v0.42.2
- v0.42.1
- v0.42.0
- v0.41.0
- v0.40.1
- v0.40.0
- v0.39.0
- v0.38.0
- v0.37.0
- v0.36.0
- v0.35.1
- v0.35.0
- v0.34.0
- v0.33.0
- v0.32.1
- v0.32.0
- v0.31.0
- v0.30.0
- v0.29.1
- v0.29.0
- v0.28.0
- dev-next
This package is auto-updated.
Last update: 2026-10-15 18:33:01 UTC
README
A Laravel website with the WebX UI admin panel on it: the
public pages are this site's theme over a shared one, the content — pages, articles, products,
menus, forms — is edited in the panel at /cms, and the modules that do the work are Composer
packages webx-ui/* in vendor/.
Two ways to run it
With Docker only — nothing else installed, no experience needed. Follow
Docker from zero step by step; it ends with the
site on http://localhost:8080 and the panel on http://localhost:8080/cms.
On a machine with PHP 8.4, Composer, Node and MySQL or MariaDB:
composer create-project webx-ui/site example.local
The questions that follow — name, domain, database, languages, modules, the first administrator
— are php artisan webx:setup, and it is the same command on a site that is already running:
run it again after installing a module and it wires in what is new and leaves the rest alone.
At the end it prints the panel's address, the login and a generated password.
Changing it, with an agent or without
- Where the styles live — which files hold the design, what is safe to change and what is not, how to see a change.
AGENTS.md— what an AI agent (Claude Code, Codex, Cursor) reads first.webx:setupwrites it andphp artisan webx:panel --synckeeps its block current; your own notes about this site go under## This project, and both it andCLAUDE.mdbelong in git. Beside them,.mcp.jsonconnects Claude Code opened in this folder to this site's own panel.- A new site — everything below, in full.
The first rule, for people and agents alike: never edit vendor/ and never copy a module into
the site. Configure it, publish its views, patch its screens — the seams are below.
What to delete first
Everything here is yours, and two things are here only so that the first page is not blank:
| what | when |
|---|---|
resources/views/demo.blade.php and its route |
as soon as the site has a front page of its own |
| the demo content | php artisan webx:demo --remove |
The demo content is rows in the database and files on disk, and the command takes out exactly
what it put in, backwards, by a journal in storage/app/webx-demo.json.
The look
webx:setup gives the site a theme of its own, theme/, standing on webx-ui/theme-default:
the layout, the header, the footer, the typography and a value for every site token come from
there, so the site opens finished. theme/ holds only what makes this site different, and it
starts empty:
| file | what goes in it |
|---|---|
theme/tokens.json |
colours, fonts, radii — "defaults": { "color-accent": "#…" } |
theme/src/css/ |
rules on the classes the shell and the modules print, var(--site-…) only |
theme/views/ |
a copy of a view, only when the markup itself has to change |
theme/assets/ |
pictures of the theme, asked for as theme_asset('img/wave.svg') |
theme/tests/ |
the theme's test, run with the site's own by php artisan test |
npm run dev rebuilds theme/src as you type; php artisan webx:theme:sync publishes the
packaged theme's files after composer update, and theme/assets/ and theme/icons/ after you
add a file there. What it publishes lands in public/themes/ under a hash of its content — kept
out of git like public/build, and cached forever by the server: /themes/ and /build/ are
immutable in docker/nginx.conf and public/.htaccess; a server of your own needs the same. A view in resources/views/components/ is above
every theme layer and wins over it, so leave layout, header and footer out of there.
A site set up with --no-theme has none of this: webx:setup writes the layout, the header and
the footer into resources/views/components/ and its styles go in resources/css/app.css.
What not to delete
routes/web.php is empty, and that is the point. Every public address of this site comes from
the address registry — a page, an article, a tag — and Route::fallback() answers them. A route
declared in web.php wins over the fallback for good, so it takes an address the panel can then
never hand out. / costs the most: the home page of the tree is an empty slug formatted to /,
and a Route::get('/') here is a home page the panel cannot even save.
The seams
Three places where the site makes the library its own:
The layout. components/layout.blade.php is <x-layout> — the theme's, or the site's own
with --no-theme — and every public view a module ships stands inside it. The agreement is two lines long — a head slot and the
default slot for the content — and config('webx-pages.layout') and its siblings are what point
at it. Keep @stack('head'): a slot is one place, and what a block type pushes cannot reach it.
The header and the footer are regions — <x-webx-blocks::region name="header" fallback="components.header" />, declared in config/webx-blocks.php: until somebody publishes
blocks there in the panel, the site prints components/header.blade.php from the theme. Without
webx-ui/module-blocks the tag prints its fallback and nothing else (AppServiceProvider).
The views. php artisan vendor:publish --tag=webx-blog-views copies a module's public views
into resources/views/vendor/, where they win over the package's. Per file, not per directory:
keep the one you rewrote and delete the rest, and those keep arriving fresh with each release.
The services. A module's behaviour is replaced through the container, in register() and not
in boot(). Where the site adds something beside what a package does rather than instead of it —
a route type, a field type, an SEO source — there is a registry to put it in, and that is the
usual answer.
Containers
Optional, and yours to delete like everything else here: Dockerfile, the two compose files
and docker/. With nothing but Docker on the machine, start from
Docker from zero.
docker compose up -d --build # the production shape docker compose -f docker-compose.yml -f docker-compose.dev.yml up # somewhere to work
One image — Composer dependencies, the front end built by this site's own Vite, then php-fpm,
nginx, a queue worker and the scheduler under supervisor — beside a MariaDB. Build it after
webx:setup: both lock files are what the image installs. Nothing here terminates TLS; the
container listens on ${APP_BIND}:${APP_PORT} and a proxy in front of it holds the
certificate. The development stack mounts this checkout into the same image, adds the Vite dev
server and a Mailpit, and caches nothing.
The variables they read are at the bottom of .env.example, in the same .env as everything
else. What a container does between starting and serving is php artisan webx:boot — run it
with --pretend to see the list.
Day to day
php artisan webx:panel --sync # after installing a module: wires it into the panel's build npm run dev # while working on the panel or the design php artisan webx:doctor # before a deploy: says what has come loose