Foundation for customizable appearance of the public booking page (colours, banner, layout — see the follow-up issues). No new settings for the user yet; this replaces how the style gets to the page.
Current state
The banner style is a generated file: modify_style in src/backend/appearance.rs copies banner.css from the data directory, replaces the /*bg-img*/ marker (or a previous background-image) with a regex and writes banner-<random>.css; the name is kept in appearance.css_name.
This is fragile: deleting the banner does not regenerate the style, check_appearance needs repair logic for a missing file on start, and ensure_data_dir copies the template from the site root.
src/components/header.rs links the generated style on every page, including the admin portal and the login page.
The primary colour of the vendor template (#696cff) is hard-coded in assets/vendor/css/core.css and theme-default.css, not a variable.
Columns appearance.style_wide and style_narrow (migration 03) are unused.
Proposed change
Appearance settings are columns of the appearance table (new migration). The public page gets them as CSS custom properties on a wrapper element (e.g. <div class="public-page" style="--rz-primary: …">), the banner image as a property or inline style as well.
A static assets/css/public.css, linked in header.rs, uses the variables and holds what is in assets/banner.css now. All its rules are scoped by the wrapper class.
The wrapper is on the public route only. The booking form embedded in the "Create booking" dialog of the admin portal (src/pages/new_reservations.rs) keeps the admin colours and the dark theme.
Remove the generated CSS: modify_style, the template copy in ensure_data_dir, the repair logic in check_appearance, the css_name handling and the <Link> to /data/<css_name>. Only uploaded images stay in the data directory.
Drop the unused columns (style_wide, style_narrow, css_name) in the migration.
Values are validated on the server before they are stored (a colour must match #rrggbb, enumerated values must be known) — they end up in a style attribute.
Acceptance
The public page looks the same as before for an installation with and without a banner, including an upgraded installation that has a generated banner-*.css (leftover files in the data directory are harmless; delete them on start if simple).
The admin portal and the login page no longer load the banner style.
Deleting the banner removes it from the page without leftovers.
deploy/ keeps working (data volume, import of an old installation with a banner), README/CLAUDE.md/rules mention of the /*bg-img*/ marker and the generated style are updated.
Unit tests for the validation and for building the style string.
Foundation for customizable appearance of the public booking page (colours, banner, layout — see the follow-up issues). No new settings for the user yet; this replaces how the style gets to the page.
## Current state
- The banner style is a generated file: `modify_style` in `src/backend/appearance.rs` copies `banner.css` from the data directory, replaces the `/*bg-img*/` marker (or a previous `background-image`) with a regex and writes `banner-<random>.css`; the name is kept in `appearance.css_name`.
- This is fragile: deleting the banner does not regenerate the style, `check_appearance` needs repair logic for a missing file on start, and `ensure_data_dir` copies the template from the site root.
- `src/components/header.rs` links the generated style on every page, including the admin portal and the login page.
- The primary colour of the vendor template (`#696cff`) is hard-coded in `assets/vendor/css/core.css` and `theme-default.css`, not a variable.
- Columns `appearance.style_wide` and `style_narrow` (migration 03) are unused.
## Proposed change
- Appearance settings are columns of the `appearance` table (new migration). The public page gets them as CSS custom properties on a wrapper element (e.g. `<div class="public-page" style="--rz-primary: …">`), the banner image as a property or inline style as well.
- A static `assets/css/public.css`, linked in `header.rs`, uses the variables and holds what is in `assets/banner.css` now. All its rules are scoped by the wrapper class.
- The wrapper is on the public route only. The booking form embedded in the "Create booking" dialog of the admin portal (`src/pages/new_reservations.rs`) keeps the admin colours and the dark theme.
- Remove the generated CSS: `modify_style`, the template copy in `ensure_data_dir`, the repair logic in `check_appearance`, the `css_name` handling and the `<Link>` to `/data/<css_name>`. Only uploaded images stay in the data directory.
- Drop the unused columns (`style_wide`, `style_narrow`, `css_name`) in the migration.
- Values are validated on the server before they are stored (a colour must match `#rrggbb`, enumerated values must be known) — they end up in a `style` attribute.
## Acceptance
- The public page looks the same as before for an installation with and without a banner, including an upgraded installation that has a generated `banner-*.css` (leftover files in the data directory are harmless; delete them on start if simple).
- The admin portal and the login page no longer load the banner style.
- Deleting the banner removes it from the page without leftovers.
- `deploy/` keeps working (data volume, `import` of an old installation with a banner), README/CLAUDE.md/rules mention of the `/*bg-img*/` marker and the generated style are updated.
- Unit tests for the validation and for building the style string.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Foundation for customizable appearance of the public booking page (colours, banner, layout — see the follow-up issues). No new settings for the user yet; this replaces how the style gets to the page.
Current state
modify_styleinsrc/backend/appearance.rscopiesbanner.cssfrom the data directory, replaces the/*bg-img*/marker (or a previousbackground-image) with a regex and writesbanner-<random>.css; the name is kept inappearance.css_name.check_appearanceneeds repair logic for a missing file on start, andensure_data_dircopies the template from the site root.src/components/header.rslinks the generated style on every page, including the admin portal and the login page.#696cff) is hard-coded inassets/vendor/css/core.cssandtheme-default.css, not a variable.appearance.style_wideandstyle_narrow(migration 03) are unused.Proposed change
appearancetable (new migration). The public page gets them as CSS custom properties on a wrapper element (e.g.<div class="public-page" style="--rz-primary: …">), the banner image as a property or inline style as well.assets/css/public.css, linked inheader.rs, uses the variables and holds what is inassets/banner.cssnow. All its rules are scoped by the wrapper class.src/pages/new_reservations.rs) keeps the admin colours and the dark theme.modify_style, the template copy inensure_data_dir, the repair logic incheck_appearance, thecss_namehandling and the<Link>to/data/<css_name>. Only uploaded images stay in the data directory.style_wide,style_narrow,css_name) in the migration.#rrggbb, enumerated values must be known) — they end up in astyleattribute.Acceptance
banner-*.css(leftover files in the data directory are harmless; delete them on start if simple).deploy/keeps working (data volume,importof an old installation with a banner), README/CLAUDE.md/rules mention of the/*bg-img*/marker and the generated style are updated.