diff --git a/.github/workflows/keycloak.yml b/.github/workflows/keycloak.yml index bce7dfb..1fc4f5a 100644 --- a/.github/workflows/keycloak.yml +++ b/.github/workflows/keycloak.yml @@ -56,6 +56,13 @@ jobs: java-version: '21' cache: 'gradle' + # The login theme is a Keycloakify project (theme/ui) that Gradle drives through yarn. + # Maven is preinstalled on the runners and is required by the Keycloakify CLI. + - name: Set up Node + uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 + with: + node-version: '22' + - name: Build with Gradle run: ./gradlew installDist diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..ff080e5 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,187 @@ +# Notes for agents + +Traps that cost real time and are not visible from reading the code. `README.md` covers how +to build and run. + +## Before changing the theme: connect the Figma MCP + +**The design is the source of truth and it lives in Figma. Check `/mcp` is connected before +touching anything visual. If it is not, say so and stop — do not work from screenshots.** + +The designs live in the OR-manager Figma file, in the "Log in pages" section — frames +`OR-login`, `OR-password`, `OR-register`, `OR-2FA` and `OR-code`, plus a third row showing +the same pages under a custom brand. Ask for the link. + +Useful calls: `get_metadata` for structure and exact box geometry, `get_design_context` for +real style values and the Vaadin component each node maps to, `get_variable_defs` for the +tokens, `download_assets` with `defaultFormat: "svg"` for logos and icons. + +## Design values, from the Figma tokens + +They are Lumo names and `@openremote/theme` already resolves them — do not hardcode. + +| | | +|---|---| +| body / links / buttons | `lumo-font-size-m` 16px | +| field labels | `lumo-font-size-s` 14px, **weight 500** | +| headings | `lumo-font-size-xl` 22px, weight 600, line-height 1.253 | +| body weight | 400, line-height 1.611 | +| **links and back-arrows** | **weight 500** — they are ``, not anchors, with a `lumo:angle-left` icon | +| card | `Spacing-L` 24px padding, **flex column, 24px gap**, radius `lumo-border-radius-l` 12px | +| heading → lead | `Spacing-S` 8px | +| label → field | 6px; fields 36px tall, radius 8px | +| primary → tertiary button | 16px (the "Actions" frame) | +| 2FA steps block | 8px between every step; QR 160px with an 8px gap to its link | + +**The logo is not the one in `ui/component/or-app/images`.** `theme/ui/public/logo.svg` comes +from Figma (`Login-logo`). In production the logo comes from `manager_config.json`; this is only the stock fallback. + +## Environment + +- Dark mode: `--blink-settings=preferredColorScheme=0`. **Not** `--force-dark-mode`, which + applies Blink's auto-darkening and gives a false pass on a theme with no dark styles. + +## Vaadin / `@openremote/or-vaadin-components` + +- **Form state goes on the component, never on the slotted ``.** Slotting the native + input is right — `SlotController.initSingle()` reuses it rather than creating its own, and it + stays in the light DOM — but `InputControlMixin` then *manages* that element. It replaces the + `id` and **silently drops `name`, `value`, `required` and `autocomplete`**, re-delegating its + own from the host. Only `type`, `autofocus`, `inputmode` and `dir` survive on the input. + + ```html + + + + + ``` + + This shipped: every field on every page came out unnamed, so the login form posted a bare + `login=` and nothing else. It is invisible in the source, in the rendered page and in a + screenshot — **the only way to see it is `new FormData(form)` in a real browser.** The + `