SkinCatalog
in package
Catalog of color variants (skins) of a front theme.
A skin is a directory <theme>/<variant>/assets/skins/<name>/ with skin.css, which contains
only CSS variable overrides. It renders after style.css, so it changes colors, radii and
shadows but leaves structure and layouts to the theme.
IMPORTANT: the service has no dependency on DefaultThemeResolver on purpose. The admin
needs the skin list too, but there the resolver holds the admin branch theme and its
availableSkins() would return nothing. The catalog works on the path the caller passes, whether
that is the currently rendered theme or the front one from the website settings.
It is the single place that reads skin.json and decides what still counts as a skin; shared by
ThemeSwitcher (visitor offer) and
SiteIdentityPresenter (admin selection).
Table of Contents
Constants
- DEFAULT_ORDER : mixed = 1000
- Skins without `order` go last, still sorted by name.
- MANIFEST_FILE : mixed = 'skin.json'
- Optional descriptive file of a skin, with keys `label`, `description`, `color` and `order` (for example `label` "Brick", `color` "#ec3013", `order` 20).
- SKIN_FILE : mixed = 'skin.css'
- File without which a directory is not a skin; the `<link>` points to it.
- SKINS_DIR : mixed = 'assets/skins/'
- Directory with skins inside a theme variant.
Methods
- exists() : bool
- Returns whether a skin of that name exists in the given theme.
- listForThemePath() : array<int, array{name: string, label: string, description: ?string, color: ?string, order: int}>
- Returns the skins of the given theme, sorted by `order` and by label on a tie.
- listForThemeSetting() : array<int, array{name: string, label: string, description: ?string, order: int}>
- Same, over the relative path from the website settings (`theme.frontend.path`, i.e.
- selectItemsForThemePath() : array<string, string>
- Returns the options for `addSelect()`: directory name to label.
- selectItemsForThemeSetting() : array<string, string>
- Returns the options for `addSelect()` over the relative path from the settings: directory name to label.
- projectRoot() : string
- Project root (`cms/www`); `app/Core/Theme/` is three levels below it.
- readManifest() : array{label?: string, description?: string, color?: string, order?: int, hidden?: bool}
- Reads `skin.json`. A broken or missing file is skipped silently: a typo in someone else's manifest must not break the offer; the skin is just offered under its directory name.
- readPrimaryColor() : string|null
- Returns `--color-primary` from the skin file, or NULL when not found.
- skinsDir() : string
Constants
DEFAULT_ORDER
Skins without `order` go last, still sorted by name.
private
mixed
DEFAULT_ORDER
= 1000
MANIFEST_FILE
Optional descriptive file of a skin, with keys `label`, `description`, `color` and `order` (for example `label` "Brick", `color` "#ec3013", `order` 20).
private
mixed
MANIFEST_FILE
= 'skin.json'
color is the color the skin shows in the appearance switcher (the dot). When missing,
--color-primary is read from skin.css itself, which is cheap because the file is a few kB.
It cannot be read from style.css this way: it is over half a megabyte and --color-primary
lies about 230 kB deep.
Without a manifest the skin is offered under its directory name. These are deliberately not
translation keys: a missing translation takes down the whole page, while a missing manifest only
loses a nice name. They are also texts of a concrete theme, not of the CMS, so they belong in its
directory, not in app/Locale/. Same reasoning as for theme.json.
"hidden": true omits the skin from listForThemePath() and the offers but keeps it working:
exists() and a direct ?_skin= link know nothing about it. For a skin that should stay on
disk but not clutter the selection.
SKIN_FILE
File without which a directory is not a skin; the `<link>` points to it.
private
mixed
SKIN_FILE
= 'skin.css'
SKINS_DIR
Directory with skins inside a theme variant.
private
mixed
SKINS_DIR
= 'assets/skins/'
Methods
exists()
Returns whether a skin of that name exists in the given theme.
public
exists(string $absThemePath, string $skin[, string $variant = 'desktop' ]) : bool
Parameters
- $absThemePath : string
- $skin : string
- $variant : string = 'desktop'
Return values
boollistForThemePath()
Returns the skins of the given theme, sorted by `order` and by label on a tie.
public
listForThemePath(string $absThemePath[, string $variant = 'desktop' ]) : array<int, array{name: string, label: string, description: ?string, color: ?string, order: int}>
Only a directory with skin.css counts as a skin, so an empty folder or a stray .DS_Store is
not offered. An empty array means the theme has no skins; the caller then renders neither the
switcher nor the admin selection.
IMPORTANT: the default variant is desktop. Skins are not duplicated for tablet and mobile;
ThemeHelper::getAssetPath() falls back to the desktop file, so
mobile gets the same skin.
Parameters
- $absThemePath : string
-
absolute path to the theme directory (
.../themes/frontend/template1/) - $variant : string = 'desktop'
Return values
array<int, array{name: string, label: string, description: ?string, color: ?string, order: int}>listForThemeSetting()
Same, over the relative path from the website settings (`theme.frontend.path`, i.e.
public
listForThemeSetting(string $relThemePath[, string $variant = 'desktop' ]) : array<int, array{name: string, label: string, description: ?string, order: int}>
/www/themes/frontend/template1/).
The project root is derived from the location of this class, the same way as
ThemeMapper::initalizeEntity(). It is deliberately
not %wwwDir%, which is computed from the outermost stack frame and points elsewhere in CLI and
harnesses.
Used by the admin, which has no absolute path to the front theme at hand (its resolver holds the admin branch theme).
Parameters
- $relThemePath : string
- $variant : string = 'desktop'
Return values
array<int, array{name: string, label: string, description: ?string, order: int}>selectItemsForThemePath()
Returns the options for `addSelect()`: directory name to label.
public
selectItemsForThemePath(string $absThemePath[, string $variant = 'desktop' ]) : array<string, string>
Parameters
- $absThemePath : string
- $variant : string = 'desktop'
Return values
array<string, string>selectItemsForThemeSetting()
Returns the options for `addSelect()` over the relative path from the settings: directory name to label.
public
selectItemsForThemeSetting(string $relThemePath[, string $variant = 'desktop' ]) : array<string, string>
Parameters
- $relThemePath : string
- $variant : string = 'desktop'
Return values
array<string, string>projectRoot()
Project root (`cms/www`); `app/Core/Theme/` is three levels below it.
private
projectRoot() : string
Return values
stringreadManifest()
Reads `skin.json`. A broken or missing file is skipped silently: a typo in someone else's manifest must not break the offer; the skin is just offered under its directory name.
private
readManifest(string $path) : array{label?: string, description?: string, color?: string, order?: int, hidden?: bool}
Parameters
- $path : string
Return values
array{label?: string, description?: string, color?: string, order?: int, hidden?: bool}readPrimaryColor()
Returns `--color-primary` from the skin file, or NULL when not found.
private
readPrimaryColor(string $cssPath) : string|null
A safety net for a skin without color in its manifest, so the switcher need not draw an empty
dot. The last occurrence is used: the CSS may declare it several times and the later one wins.
Parameters
- $cssPath : string
Return values
string|nullskinsDir()
private
skinsDir(string $absThemePath, string $variant) : string
Parameters
- $absThemePath : string
- $variant : string