* feat(themes): free-form community themes with a security floor
Community themes are no longer token-only. The in-app guard
(validateThemeCss) now enforces only a security floor — no network
(@import / non-data url()), no scripts (<style>/<script>/expression()/
javascript:/-moz-binding), no @property, @keyframes namespaced as <id>-,
and a 256 KB cap — and otherwise allows any selectors, structure and
animations. validateThemePackage checks the manifest plus that floor.
Themes can react to app state via same-element attributes set on the theme
root: data-playing, data-fullscreen, data-sidebar-collapsed, data-lyrics-open.
The local-import confirm dialog now notes that imported themes aren't
reviewed and are installed at the user's own risk. Removes the now-unused
bundled token whitelist.
* docs(themes): note free-form themes in the Theme Store entry
Add PR #1015 and a free-form bullet to the still-unreleased Theme Store
changelog and credits entry.
* feat(themes): validate and extract locally imported theme packages
Add the backend + validation half of local theme import: users will be
able to load a theme packaged as a .zip (manifest.json + theme.css).
- `import_theme_zip` Tauri command unpacks only manifest.json + theme.css
from the archive, outside the webview, with an archive-size cap,
per-entry uncompressed caps, and path-traversal rejection.
- `validateThemePackage` runs the full theme-store contract in-app: the
manifest schema (field patterns copied from the repo schema), the CSS
token whitelist with all core tokens required, color-scheme matching
the declared mode, data-URI restricted to the arrow token, and a guard
against ids that collide with built-in themes. The existing
`validateThemeCss` containment guard is reused and runs again at
injection time. The contract token list is a byte-identical copy of the
themes repo's allowed-tokens.json.
Covered by validateThemePackage tests for every rejection class.
* feat(themes): add the Import a theme section to the Themes tab
A dedicated section between the theme scheduler and the Theme Store lets
users import a theme from a local .zip. After the package validates, a
confirmation dialog names the theme and its author before it is installed.
A rejected import shows a plain-language explanation aimed at end users;
the raw contract diagnostics (token names, missing fields) are tucked
into a collapsible "Technical details" block for theme authors. Fully
localised across all nine languages.
* docs(themes): changelog + credits for local theme import
Fold the local .zip import (and the store pagination / refresh-scroll
polish) into the still-unreleased Theme Store entry rather than a new
section, and extend the credits line. PRs #1011 and #1012.