Skip to content

feat(ui): create the first branded Blade component set#32

Merged
ibourgeois merged 1 commit into
mainfrom
codex/6-ui-kit
Apr 10, 2026
Merged

feat(ui): create the first branded Blade component set#32
ibourgeois merged 1 commit into
mainfrom
codex/6-ui-kit

Conversation

@ibourgeois
Copy link
Copy Markdown
Contributor

Closes #6\n\nSummary:\n- Adds reusable Blade primitives for buttons, inputs, selects, textareas, badges, avatars, panels, dropdowns, modals, headers, and shell nav items\n- Refactors the app shell and home screen to consume shared components\n- Adds Pest coverage for the shared component outputs\n\nValidation:\n- vendor/bin/pint --dirty --format agent\n- php artisan test --compact\n- npm run build

Copilot AI review requested due to automatic review settings April 10, 2026 10:10
@ibourgeois ibourgeois merged commit 7dd3835 into main Apr 10, 2026
3 checks passed
@ibourgeois ibourgeois deleted the codex/6-ui-kit branch April 10, 2026 10:11
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces an initial set of branded, reusable Blade UI primitives and refactors the shell/home view to consume them, with initial Pest render coverage for key components.

Changes:

  • Added anonymous Blade UI components (button, input/select/textarea, badge/avatar, panel/page-header, dropdown/modal).
  • Refactored the app shell navigation items into dedicated x-app.* components and updated the home screen to use x-ui.* primitives.
  • Added a feature test to render and assert basic output for several shared UI components.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/Feature/Ui/UiComponentsTest.php Adds Blade render assertions for shared UI components.
resources/views/home.blade.php Refactors home screen markup to use new x-ui.page-header, x-ui.panel, and x-ui.badge.
resources/views/components/ui/button.blade.php Adds a reusable button primitive with variants and default type.
resources/views/components/ui/input.blade.php Adds a labeled input primitive with optional error rendering.
resources/views/components/ui/textarea.blade.php Adds a labeled textarea primitive with optional error rendering.
resources/views/components/ui/select.blade.php Adds a labeled select primitive with optional error rendering and slot options.
resources/views/components/ui/badge.blade.php Adds a badge primitive with tone-based styling.
resources/views/components/ui/avatar.blade.php Adds an avatar primitive with initials/name fallback and size variants.
resources/views/components/ui/panel.blade.php Adds a panel/container primitive with optional title/subtitle header.
resources/views/components/ui/page-header.blade.php Adds a page header primitive with eyebrow/title/description and actions region.
resources/views/components/ui/dropdown.blade.php Adds a details/summary-based dropdown primitive.
resources/views/components/ui/modal.blade.php Adds a “modal” container primitive with optional title.
resources/views/components/layouts/app-shell.blade.php Switches inline toolbar/context nav markup to new x-app.* components and minor class tweaks.
resources/views/components/app/toolbar-item.blade.php Extracts toolbar item link rendering into a reusable component.
resources/views/components/app/context-nav-item.blade.php Extracts context nav item link rendering into a reusable component.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +15 to +19
<input {{ $attributes->class([$fieldClasses]) }}>

@if ($error)
<span class="text-sm text-red-500">{{ $error }}</span>
@endif
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When $error is present, the input isn’t marked/linked for assistive tech: consider setting aria-invalid="true" and associating the error text via aria-describedby (using a stable id from $attributes->get('id') or derived from name). This makes validation errors discoverable to screen readers.

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +19
<select {{ $attributes->class([$fieldClasses]) }}>
{{ $slot }}
</select>

@if ($error)
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When $error is present, the select isn’t marked/linked for assistive tech: consider setting aria-invalid="true" and associating the error text via aria-describedby (using a stable id from $attributes->get('id') or derived from name).

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +19
<textarea {{ $attributes->class([$fieldClasses]) }}></textarea>

@if ($error)
<span class="text-sm text-red-500">{{ $error }}</span>
@endif
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When $error is present, the textarea isn’t marked/linked for assistive tech: consider setting aria-invalid="true" and associating the error text via aria-describedby (using a stable id from $attributes->get('id') or derived from name).

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +7
<div {{ $attributes->class(['rounded-md bg-panel p-5']) }}>
@if ($title)
<h2 class="text-base font-semibold text-copy">{{ $title }}</h2>
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component is named modal, but the markup is only a styled container and doesn’t provide dialog/modal semantics (e.g., role="dialog", aria-modal, labeling via aria-labelledby, backdrop/focus management). Either rename it to reflect that it’s a non-modal surface, or implement the expected modal semantics to avoid consumers shipping an inaccessible/non-modal “modal”.

Suggested change
<div {{ $attributes->class(['rounded-md bg-panel p-5']) }}>
@if ($title)
<h2 class="text-base font-semibold text-copy">{{ $title }}</h2>
@php
$titleId = $title ? 'modal-title-' . uniqid() : null;
@endphp
<div
role="dialog"
aria-modal="true"
@if ($titleId) aria-labelledby="{{ $titleId }}" @endif
tabindex="-1"
{{ $attributes->class(['rounded-md bg-panel p-5']) }}
>
@if ($title)
<h2 id="{{ $titleId }}" class="text-base font-semibold text-copy">{{ $title }}</h2>

Copilot uses AI. Check for mistakes.
])

<details {{ $attributes->class(['group relative']) }}>
<summary class="list-none rounded-md bg-main px-3 py-2 text-sm font-medium text-copy marker:hidden">
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

marker:hidden is unlikely to affect the <summary> disclosure marker (::marker doesn’t support display: none). Since list-none is already present, consider removing marker:hidden, or hide the marker via a targeted CSS rule (e.g., summary::-webkit-details-marker { display: none; }) if needed.

Suggested change
<summary class="list-none rounded-md bg-main px-3 py-2 text-sm font-medium text-copy marker:hidden">
<summary class="list-none rounded-md bg-main px-3 py-2 text-sm font-medium text-copy">

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +16
it('renders the shared form controls', function (): void {
$rendered = Blade::render(<<<'BLADE'
<x-ui.input label="Name" />
<x-ui.textarea label="Summary"></x-ui.textarea>
<x-ui.select label="State">
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions Pest coverage for shared component outputs, but this file doesn’t currently exercise some newly added components (e.g., x-ui.panel, x-ui.page-header, x-ui.dropdown, x-ui.modal). Adding minimal render assertions for them would help catch markup regressions and better match the stated coverage goals.

Copilot uses AI. Check for mistakes.
])

<a
href="{{ $href }}"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding aria-current when $current is true (e.g., aria-current="page") so the active toolbar item is announced correctly to screen readers, not just styled visually.

Suggested change
href="{{ $href }}"
href="{{ $href }}"
@if ($current) aria-current="page" @endif

Copilot uses AI. Check for mistakes.
])

<a
href="{{ $href }}"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding aria-current when $current is true (e.g., aria-current="page") so the active context nav item is announced correctly to screen readers, not just styled visually.

Suggested change
href="{{ $href }}"
href="{{ $href }}"
@if($current) aria-current="page" @endif

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(ui): create the first branded Blade component set

2 participants