diff --git a/landing-e2e/playwright.config.mts b/landing-e2e/playwright.config.mts index 779181c..14f4f3b 100644 --- a/landing-e2e/playwright.config.mts +++ b/landing-e2e/playwright.config.mts @@ -12,6 +12,19 @@ const here = dirname(fileURLToPath(import.meta.url)); const workspaceRoot = resolve(here, '..'); const baseURL = process.env['BASE_URL'] || 'http://localhost:4200'; +/** + * The dev server is started on whatever port `BASE_URL` names, rather than + * always 4200. + * + * `reuseExistingServer` means Playwright will happily adopt whatever is already + * listening there — and if that is a different project's dev server, every test + * fails with "element(s) not found" while the real cause is that the page under + * test was never served. Set BASE_URL to move both halves at once: + * + * BASE_URL=http://localhost:4280 npx nx e2e landing-e2e + */ +const port = new URL(baseURL).port || '4200'; + export default defineConfig({ testDir: './src', outputDir: resolve(workspaceRoot, 'dist/.playwright/landing-e2e/test-output'), @@ -25,7 +38,7 @@ export default defineConfig({ trace: 'on-first-retry', }, webServer: { - command: 'npx nx run landing:serve', + command: `npx nx run landing:serve --port=${port}`, url: baseURL, reuseExistingServer: true, timeout: 180_000, diff --git a/landing/src/app/core/copy.ts b/landing/src/app/core/copy.ts index e6f12f8..05efe15 100644 --- a/landing/src/app/core/copy.ts +++ b/landing/src/app/core/copy.ts @@ -78,6 +78,7 @@ export interface Copy { email: string; organisation: string; hours: string; + hoursHint: string; message: string; messageHint: string; consent: string; @@ -167,6 +168,7 @@ const es: Copy = { email: 'Correo', organisation: 'Organización', hours: 'Horas por semana', + hoursHint: 'Por ejemplo, 4', message: 'Mensaje', messageHint: 'Mínimo 20 caracteres.', consent: 'Acepto que guardéis mis datos para responderme.', @@ -264,6 +266,7 @@ const en: Copy = { email: 'E-mail', organisation: 'Organisation', hours: 'Hours per week', + hoursHint: 'For example, 4', message: 'Message', messageHint: 'At least 20 characters.', consent: 'I agree to have my details stored so you can reply.', @@ -361,6 +364,7 @@ const ca: Copy = { email: 'Correu', organisation: 'Organització', hours: 'Hores per setmana', + hoursHint: 'Per exemple, 4', message: 'Missatge', messageHint: 'Mínim 20 caràcters.', consent: 'Accepto que deseu les meves dades per respondre’m.', diff --git a/landing/src/app/ui/contact-form.scss b/landing/src/app/ui/contact-form.scss index a618085..35072e4 100644 --- a/landing/src/app/ui/contact-form.scss +++ b/landing/src/app/ui/contact-form.scss @@ -28,3 +28,28 @@ margin: 0; color: var(--pi-color-warn, #d64545); } + +// The hours field sits inside an @if, and that is what breaks its label. +// +// Angular Material measures an outlined field's floating label once, on init, +// and writes the result to the element as an inline +// `transform: var(--mat-mdc-form-field-label-transform, translateY(-50%) …)`. +// A field created inside a conditional block is measured before it has any +// geometry, so the value it keeps is the unfloated one: the label ends up 5px +// above the wrapper instead of 18, straddling the 2px outline and struck +// through by it. +// +// `@pi/ui` already publishes the right geometry for every other field +// (`translateY(-3rem) scale(1)`, a 48px label box), and that rule matches this +// one too — it simply loses to the inline style. `!important` is what beats an +// inline declaration, and it is restating the library's own values, not +// inventing new ones. +:host ::ng-deep .pi-field.pi-form-field__number { + .mdc-notched-outline .mdc-floating-label { + height: var(--pi-spacing-xxxx-large) !important; + } + + .mdc-text-field:not(.mat-form-field-no-animations) .mdc-floating-label { + transform: translateY(-3rem) scale(1) !important; + } +} diff --git a/landing/src/app/ui/contact-form.ts b/landing/src/app/ui/contact-form.ts index 03c929c..1692f59 100644 --- a/landing/src/app/ui/contact-form.ts +++ b/landing/src/app/ui/contact-form.ts @@ -115,7 +115,17 @@ type Kind = 'contribute' | 'request'; {{ copy().form.organisation }} } @else { - + + {{ copy().form.hours }} }