Skip to content

Latest commit

 

History

History

dev

Folders and files

README.md

Local theme development

Use the setups in this folder to reproduce CSS bugs and develop app themes. Follow the theme.park setup guide and the app's instructions in tp-docs. Record the local startup commands and verification steps in dev/<app>/README.md.

Current setup

The NZBGet setup uses Compose to run the official app Docker mod with local CSS. Its seed script creates paused dummy downloads.

serve.py uses Python's standard HTTP server and adds Cache-Control: no-store. The Compose service mounts the checkout's CSS and resources read-only. File edits appear on refresh without a build.

There is no shared nginx proxy or theme.park image setup yet. Add and test one when an app task needs it, using the guidance below.

The Dozzle setup runs synthetic container logs and injects CSS through a local nginx proxy. It includes Dozzle's CSP and streaming API exceptions, with a direct port for native comparisons.

The Pi-hole setup seeds synthetic network devices and uses nginx injection. Its notes explain the Network page's dependency on opaque CSS colors and how to reproduce a native stylesheet replacement.

The Nginx Proxy Manager setup uses the official startup script and includes browser checks for theme variables and UI states.

The Jellyfin setup uses synthetic movies, built-in Custom CSS, and nginx subfiltering for the dashboard. Its notes cover the Jellyfin 12 palette and table backgrounds that do not follow the app's CSS variables.

Development logins

Use admin / admin for disposable app logins, as requested by the maintainer. If the app enforces an email address, use admin@example.com. If it rejects the short password, use adminadmin when accepted. Document any exception beside the app URL so the maintainer does not have to ask for credentials. These defaults apply to local test instances, not existing user accounts outside that setup.

Choose hosting and injection separately

The CSS host serves stylesheets. The injection method makes the app load them. The theme.park image handles hosting. The app still needs a way to load the CSS.

CSS host When to use it
Local Python server Edit source CSS and refresh the app. Load the app base CSS followed by the chosen theme option.
theme.park Docker image Check packaged files, generated theme URLs, startup, or subfolder handling. Build from the checkout to test local edits.

The documented image is ghcr.io/themepark-dev/theme.park. See the Docker setup for tags, ports, configuration, and TP_URLBASE. A pulled release image does not contain edits in this checkout.

The current image startup script copies bundled files from /app/themepark into /config/www, runs themes.py, and changes configuration ownership. Use disposable configuration when testing the image. Do not mount the working checkout at /config/www. Startup can overwrite its files or change their ownership. Rebuild after editing files, or set up and verify a way to copy those edits into the test container.

The image's nginx configuration disables caching and rewrites asset paths for its subfolder endpoint. The Python server does neither subfolder rewriting nor theme generation. When editing source CSS, link the base stylesheet and theme option separately. To test a generated <app>/<theme>.css URL, generate wrappers in a temporary directory or use the image. Confirm the browser loads every imported file.

Documentation marker Injection method
🐳 LinuxServer Docker mod, configured to load the local CSS host.
🔥 Documented Hotio/S6 startup script mount; do not assume DOCKER_MODS works.
⚙️ The app's built-in CSS setting, using locally served styles.
No method marker Local reverse proxy using the subfiltering guide.
⚠️ Read the app-specific setup requirements in addition to the chosen method.

Reproduce the reporter's installation method where supported. You can try styles in the browser during investigation. Verify the final files through the chosen installation method after reloading the page.

Local reverse proxy

Use an nginx container on the application's Compose network. The browser opens the proxy's loopback-bound port. Nginx forwards requests to the app's service name and internal port. Stylesheet links must use an address the browser can reach. Docker service names usually resolve only inside Docker networks. Inside the nginx container, localhost refers to that container.

Follow the nginx subfilter recipe: request uncompressed upstream content, inject once, and keep injection out of API locations. Start with the app and CSS host on separate ports so their /css and /resources paths do not collide.

Make the injection point and proxy exceptions app-specific. For example, Sonarr documents </body> injection. Other apps may need CSP adjustments or a separate unbuffered API location. Apply exceptions only where required by the app's documented setup. Verify login, redirects, and stylesheet order in the running app. Check streaming and WebSockets if the app uses them. Use the app's documented injection point.

Workflow for an app task

Start a task branch from freshly fetched origin/develop and merge the finished work back into develop. Use testing only for potentially breaking changes that could disrupt users of develop. Ordinary fixes do not need to pass through testing; disruption for users of that branch is accepted. The maintainer's explicit authorization is still required before pushing or publishing changes.

  1. Read the report and docs. Record the app version, injection method, theme, browser, viewport, and steps needed to reach the problem.
  2. Reuse dev/<app>. If absent, add a minimal Compose file and README. Record the image tag, local ports, dependencies, setup and login steps, injection method, and commands to stop or reset the app. Check occupied ports before starting.
  3. Give the test instance its own configuration. Add dummy data or a seed script when an empty installation cannot display the affected screen. Keep real credentials and private data out of tracked files. If an app needs an existing instance or user-provided access, record that requirement.
  4. Confirm local CSS and assets load, reproduce the bug, and capture the original appearance before editing. Record unrelated existing defects.
  5. Inspect DOM and computed styles, compare upstream changes when useful, and make the smallest appropriate source change using theme variables.
  6. Reload through the real injection method. Exercise relevant states such as hover, focus, selection, dialogs, and empty/populated views. Check native light/dark modes where supported. Use the background checks below to choose theme options, plus a light community palette when relevant. Include the reported browser and responsive layout where practical. Record any substitutions.
  7. Inspect screenshots as well as computed styles. For shared CSS changes, check other apps that import it. Run relevant generation and build checks in a temporary directory.
  8. Record the cause, patch, image tag, app version, browser, theme, viewport, reproduction steps, evidence, and gaps. Store screenshots and run-specific results under ignored dev/artifacts/<app>/<issue>/. Document reusable discoveries using the guidance below before finishing.
  9. Keep PR descriptions short and apply the unslop skill. State the fixes and relevant validation. Include before/after screenshots in PR descriptions for visual changes, including bug fixes and theme rewrites. Use the same app version, theme, viewport and interaction state where possible. Keep the full local evidence set for verification.
  10. Leave changes local for review. Report which test services remain running and how to stop them. Stop only services created for the task. Delete saved configuration only when resetting the test instance. Never push or deploy without the maintainer's explicit instruction.

For a new theme.park application, also add the app base stylesheet, any required resources, and the appropriate documentation/navigation entries in tp-docs. Follow CONTRIBUTING.md, including screenshots of all official theme options. Adding a local environment for an already supported app does not require adding another application theme.

Older issues and UI replacements

Record the issue date and reported app version separately. When the report omits a version, do not infer an exact release from its date or screenshot. Check the current stable release, its UI migration notes, and the history of the app's base CSS before writing selectors for an old screenshot.

Run the current app with its native CSS and with the existing theme. Compare the affected component plus other main screens. Distinguish a missing selector from a replaced component system. Inspect the current DOM, framework, and color variables. Zero matches for old selectors are evidence for the inspected screens, not proof that those selectors are unused on every supported version.

If the UI was broadly rebuilt, report whether support needs a theme rebuild instead of a small bug fix. Explain the broken areas, reusable styling hooks, and verification scope. Let the maintainer decide whether that investment fits continued support. Do not silently deprecate the app or present a partial sidebar patch as restored support. Keep the working local setup and findings available for that decision.

Background checks

Test background types as well as colors. Use at least these cases when changing backgrounds, transparency, dialogs, or panels:

Theme What it checks
Nord Solid colors, including distinct modal body and header/footer colors.
Aquamarine A radial page gradient and a linear modal gradient.
Hotline A linear page gradient with a different direction from its modal gradient.
Plex, when layers matter Several page gradients with a solid fallback color.

Read the component's variables before testing. A radial page background does not imply a radial modal background. If no existing option exercises the value needed for a check, use a temporary custom option and label it in the results.

Variables such as --main-bg-color and --modal-bg-color can contain a full background declaration, including an image, position, size, repeat, and attachment. Use background to accept that value. background-color accepts only a color, while background-image cannot accept the extra background settings. A declaration with an incompatible variable can fail after variable substitution even though the browser parsed the stylesheet.

Inspect the visible element and its children. A solid child panel can cover the correct gradient on its parent. Compare the dialog shell, body, header, and footer separately. The header, body background, and footer can each have a different color or gradient. Verify each against its own variable; matching colors are not a requirement. If a theme gives them identical values, test with three distinct temporary values to expose accidental variable substitutions. Check text contrast and borders in each section. Resize and scroll the dialog to catch gradient seams, repeated backgrounds, or transparent areas that reveal the page instead of the dialog. Check which element actually scrolls. A phone layout may scroll the document instead of the modal body. Confirm that the scroll position changed.

Wait for stylesheet loads, fonts, and modal animations before taking screenshots. When switching themes in the browser, reload the final setup through its normal injection method as well. Inspect the screenshots after the computed-style checks.

For hover bugs, move a real browser pointer onto the control. Dispatching a mouseover event from JavaScript does not activate CSS :hover. Compare the background and text before hover, during hover, and after moving away. Inspect the winning selectors, including classes inside :not(), before adding specificity or !important. Check other uses of the same button class and keep selected, disabled, and status-colored controls distinguishable. Include custom controls such as clickable icon containers in the inspection; an app's shared .btn rules may not cover them. For sprite icons, check both the image URL and the rectangle selected by each state's background position.

Defects found while investigating

App updates often affect more than the component named in an issue. Inspect nearby controls and at least one other use of a shared component. Keep a short record of each additional defect, its reproduction steps, and whether it is part of the current fix. Tell the maintainer about remaining defects rather than treating them as covered by the original issue.

Save reusable navigation and debugging notes in the app README. Keep screenshots and detailed results in the ignored artifact directory. A useful note names the element, the rule that caused the problem, and the checks that exposed it.

Keep lessons for the next session

Document discoveries that would save another session time or prevent a repeated mistake. Apply the unslop skill to every note. Put shared workflow lessons here and app-specific setup, navigation, selectors, and exceptions in dev/<app>/README.md. Keep AGENTS.md focused on instructions for doing the work. Update an existing note when it covers the same subject.

A useful note explains the observed problem, its cause, and the command or interaction that resolves it. Include the app version when behavior may change between releases. State what was verified and label untested ideas. Record maintainer-approved exceptions with their reason and scope so another session does not undo them. Keep temporary paths, full logs, and individual run results under ignored dev/artifacts/<app>/<issue>/. Do not copy a session transcript into the README or include credentials and private data.

Preserve the review instance

When the maintainer is checking a running instance, preserve its selected theme and profile settings. Separate browser contexts may still share settings stored by the app on its server. Dozzle shares its profile between the native and proxy URLs, so automated appearance changes can affect the maintainer's tabs.

Check Compose defaults before recreating services. A theme selected with an inline environment variable applies to that command only. Repeat the override when recreating the proxy to avoid reverting the review instance to its default theme. Record the selected theme and startup command in the task artifacts.

Screenshots in pull requests

Before/after screenshots are required for visual changes. Embed the images in the PR description so reviewers can compare them without downloading files. Use GitHub attachments or existing repository assets where suitable. If an attachment is unavailable, commit only the selected review images under dev/<app>/screenshots/ and embed their immutable raw GitHub URLs. Keep full test runs and intermediate captures under ignored dev/artifacts/.

For a documentation gallery refresh, show the previous and updated gallery images in the docs PR and label their app versions when known. Link the related theme PR. Changes with no visible result, such as workflow instructions, do not need screenshots.

Refresh documentation screenshots

For a theme refresh, check the app's page in the separate tp-docs repository for screenshots that still show the old UI. Reuse verified captures of the final CSS, with synthetic data and consistent viewport sizes.

Inspect the page template and mkdocs.yml before replacing assets. Dozzle's gallery loops over config.extra.themes and expects docs/site_assets/dozzle/<theme>.png. Existing files can be missing options that the gallery already references. Compare the configured list with the captures instead of replacing only the images already present.

Build MkDocs, open the rendered app page, and check that every gallery image loads and shows the intended theme. A successful build alone does not establish that image URLs work. Keep the docs change in a separate branch and PR targeting develop; publishing still requires the maintainer's instruction.

Publishing development files

The Pages workflow publishes the repository root and excludes dev and AGENTS.md from all three deployment branches. This also excludes local artifacts nested under dev. Keep those exclusions when changing deployment steps; Git ignore rules alone do not control the published files. The application Dockerfiles copy specific asset paths, which exclude these development files. Keep tooling changes separate from CSS fixes for review.

Component libraries and CSS modules

Bazarr's Mantine update replaced the old bazarr-* classes, but retained public classes such as mantine-Button-root. Check the app's theme provider and rendered DOM before treating generated CSS-module names as a support blocker. Prefer public component classes, state attributes and semantic containers. Document any module-name prefix you still need in the app README.

Check for collisions between theme variables and the component library's local variables. Bazarr's --button-color means text color in Mantine and background color in theme.park. A theme alias resolved at the document root avoids the component's local override. Test normal, hover and disabled states after changing variable mappings, and preserve explicit status colors.