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.86.0
- webx-ui/module-auth: ^0.86.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.86.0
- v0.85.0
- v0.84.0
- v0.83.0
- v0.82.0
- v0.81.0
- v0.80.0
- v0.79.1
- v0.79.0
- v0.78.0
- v0.77.0
- v0.76.0
- 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-23 15:16:35 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 — and the commands setup leaves to you. Setup writes no block types and seeds no demo: the same command makes staging and production sites, and a block type reaches those only when somebody imports it. On a dev copy, run what it printed, in that order:
php artisan webx:blocks:import --theme --publish # the theme's block types php artisan webx:blocks:offered --install # the blocks the modules offer php artisan webx:demo # demo content, on top of both
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 (the demo content only when you seeded it):
| 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 site believes that proxy's X-Forwarded-* only from private networks and
localhost — config/trustedproxy.php; a proxy elsewhere (a CDN) is named in TRUSTED_PROXIES.
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