fix: remove whitespace below hero tabs on mobile#198
Conversation
- Add min:20 validation to contact form message field - Use API_DOMAIN env var for Scribe docs base URL when set
Hidden tab panels used visibility:hidden which preserves layout space, causing the tallest panel (AI Agent chat) to force container height for all tabs. Switch hidden panels to absolute positioning so only the active panel determines container height.
There was a problem hiding this comment.
Pull request overview
Adjusts the marketing home hero tab panel behavior to avoid excess vertical whitespace on mobile by changing how inactive panels are hidden. The PR also includes unrelated configuration and validation tweaks.
Changes:
- Update hero tab panels to use
absolutepositioning when hidden, aiming to prevent hidden content from contributing to layout height. - Update Scribe API docs
base_urlto preferapp.api_domainwhen set. - Tighten contact form validation by requiring a minimum message length.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| resources/views/home/partials/hero.blade.php | Changes tab panel hiding/showing mechanics to reduce mobile whitespace. |
| config/scribe.php | Alters generated API docs base URL selection logic. |
| app/Http/Requests/ContactRequest.php | Adds min:20 validation rule for contact messages. |
Comments suppressed due to low confidence (1)
resources/views/home/partials/hero.blade.php:201
- During the animated tab switch,
showPanel(nextPanel)makes the next panel participate in grid layout again, but the previous (currently visible) panel remains in-flow until the animation promise resolves andhidePanel(currentPanel)runs. In a grid, both panels will contribute to the row sizing during that interval, so switching away from the tall AI panel can still keep the container height tall (and whitespace visible) for the duration of the animation. Consider movingcurrentPaneltoabsolute inset-0(withoutinvisible) before starting the animation so only the active panel determines layout height while the outgoing panel crossfades on top.
showPanel(panel) {
panel.classList.remove('invisible', 'absolute', 'inset-0');
panel.style.position = 'relative';
panel.style.zIndex = '1';
},
hidePanel(panel) {
panel.classList.add('invisible', 'absolute', 'inset-0');
panel.style.position = '';
panel.style.opacity = '';
panel.style.transform = '';
panel.style.willChange = '';
panel.style.zIndex = '';
},
| 'base_url' => config('app.api_domain') ? 'https://'.config('app.api_domain') : config('app.url'), | ||
|
|
There was a problem hiding this comment.
This hardcodes the scheme to https and doesn’t preserve the optional port the way URL::getApiUrl() does. In local/dev (often http) or when app.url includes a port, the generated Scribe base URL can be incorrect. Suggest mirroring the logic in MacroServiceProvider::getApiUrl (derive scheme+port from config('app.url'), then apply api_domain) so docs URLs match the rest of the app.
| 'base_url' => config('app.api_domain') ? 'https://'.config('app.api_domain') : config('app.url'), | |
| 'base_url' => (static function (): string { | |
| $appUrl = config('app.url'); | |
| $apiDomain = config('app.api_domain'); | |
| if (! is_string($appUrl) || $appUrl === '') { | |
| return ''; | |
| } | |
| if (! is_string($apiDomain) || $apiDomain === '') { | |
| return $appUrl; | |
| } | |
| $parsed = parse_url($appUrl); | |
| if ($parsed === false || ! isset($parsed['scheme'], $parsed['host'])) { | |
| return $appUrl; | |
| } | |
| $scheme = $parsed['scheme']; | |
| $port = isset($parsed['port']) ? ':'.$parsed['port'] : ''; | |
| return "{$scheme}://{$apiDomain}{$port}"; | |
| })(), |
| // The base URL displayed in the docs. | ||
| // If you're using `laravel` type, you can set this to a dynamic string, like '{{ config("app.tenant_url") }}' to get a dynamic base URL. | ||
| 'base_url' => config('app.url'), | ||
| 'base_url' => config('app.api_domain') ? 'https://'.config('app.api_domain') : config('app.url'), |
There was a problem hiding this comment.
PR description focuses on removing mobile whitespace in the home hero tabs, but this PR also changes Scribe docs base URL behavior. Please either update the PR description/test plan to cover this change (and why it’s included) or split it into a separate PR so the UI fix can be reviewed/rolled back independently.
| 'name' => ['required', 'string', 'max:255'], | ||
| 'email' => ['required', 'email:rfc,dns', 'max:255'], | ||
| 'company' => ['nullable', 'string', 'max:255'], | ||
| 'message' => ['required', 'string', 'max:5000'], | ||
| 'message' => ['required', 'string', 'min:20', 'max:5000'], | ||
| ]; |
There was a problem hiding this comment.
This changes validation behavior (message now requires a minimum length). There are Feature tests for public pages, but none appear to cover the contact form submission/validation, so this behavior can regress silently. Add Pest feature tests covering: (1) message < 20 chars fails validation, and (2) a valid submission sends the mail and redirects with success.
Summary
visibility: hiddenwhich preserves layout spaceabsolutepositioning so only the active panel determines container heightTest plan