Skip to content

Weave a new theme

$ grim make:theme shop-front --activate

A new site needs its own face, and a theme is where that lives: the layouts, the pages, the stylesheet and the TypeScript entry point Vite builds from. grim make:theme lays down a theme with a layout, an index page and error pages already in place, so you start by changing a page instead of wiring an empty directory.

Reach for it at the start of a project's frontend, or when the admin should look different for one client. Editing a theme that already exists needs no command at all.

Usage

$ grim make:theme shop-front --activate       # frontend theme, switched on in .env
$ grim make:theme shop-admin --type=admin     # a theme for the admin
$ grim make:theme shop-front --no-repo        # local only, nothing on GitHub

Run it from the project directory. The slug is lowercase kebab-case and starts with a letter; anything else is refused with Theme slug must be lowercase kebab-case (e.g. boulder24, my-theme).

Arguments and options

Scaffold a new theme under resources/themes/{type}/{slug}/ (with validate.yml + GitHub repo)

Usage

grim make:theme [-t|--type TYPE] [-d|--description DESCRIPTION] [-a|--activate] [--no-repo] [--private] [--public] [--org ORG] [--use-existing] [--skip-push] [--] <slug>

Arguments

Argument Description
slug Theme slug in kebab-case (e.g. boulder24) (required)

Options

Option Description
-t, --type=TYPE Theme type: frontend or admin (default: frontend)
-d, --description=DESCRIPTION Short description for theme.json
-a, --activate Patch .env to activate this theme
--no-repo Skip GitHub repository creation + git init
--private Create the GitHub repo as private (default)
--public Create the GitHub repo as public
--org=ORG GitHub org (or user) to create the repo under (default: grimoiry)
--use-existing If the remote repo already exists, reuse it instead of failing
--skip-push Init local git + attach remote but do not push

What it actually does

Each step is printed with a number and its duration.

  1. Scaffolds resources/themes/<type>/<slug>/. What lands there depends on the type, see below. The version in theme.json is the version of the core the project is on.
  2. Copies the validation workflow to .github/workflows/validate.yml inside the theme.
  3. Patches .env, only with --activate: THEME_FRONTEND=<slug> and VITE_THEME_FRONTEND=${THEME_FRONTEND}, or the ADMIN pair for an admin theme. Existing lines are replaced, missing ones appended.
  4. Makes it a git repository with one commit on main.
  5. Creates the GitHub repository under --org, private unless --public, attaches it as origin and pushes main.
  6. Pushes a first version tag matching the version in theme.json. A theme with no release cannot be resolved by a constraint in any project's grim.json, so this is what makes it installable elsewhere. --skip-push leaves out both pushes.
  7. Prints a summary. Path, type, whether it was activated, the repository URL and a Published row.

Steps 4 to 6 are allowed to fail. A missing git identity or a token that cannot create repositories produces a warning, the run continues, and the theme is complete on disk.

What each type contains

frontend admin
Always theme.json, app.blade.php, functions.php theme.json, app.blade.php, functions.php
Entry points ts/frontend.ts, ts/bootstrap.ts, css/frontend.css ts/app.ts, css/app.css
Views layouts/standard.blade.php, pages/index.blade.php, a Container component, an email layout None
Error pages 403, 404, 419, 429, 500, 503 None
Repository grim-theme-<slug> grim-theme-admin-<slug>

Pitfalls

--activate needs an .env

.env not found at <project>/.env — run `grim install` / `grim up` first to generate it. stops the run after the theme was scaffolded. Generate the .env, then set the two variables by hand; a second make:theme would refuse because the directory exists.

Published: no is easy to miss

When a publish step fails the command still ends in success, with no — 2 step(s) skipped in the Published row of the summary. Below it grim prints the commands to finish by hand: change into the theme directory and run gh repo create with --source=. --push.

The theme is not written into grim.json

make:theme touches .env at most. A colleague who clones the project gets the theme only if grim.json names it. Once the theme is published, grim require shop-front --frontend writes it into the slot and the lock. By hand, the entry in themes.frontend or themes.admin reads <slug>:<constraint>, for example shop-front:~2.5. When the slot declares some other theme, grim build warns that .env names one grim.json does not, and builds with the .env value.

After it finishes

Without --activate the command ends by naming the variable to set: THEME_FRONTEND=shop-front. Add VITE_THEME_FRONTEND=${THEME_FRONTEND} next to it, so that Vite builds the same theme the app renders. Containers read .env when they are created, so bring the stack up again.

$ grim down
$ grim up

Check the manifest with grim manifest:validate whenever you edit theme.json.

Curses it can raise

Tailwind classes from modules are missing in the built CSS

The theme build does not see the templates of installed modules.

Recipes that use it

The idea underneath