AI & workflows
Ai Prompter code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/ai-prompter.blade.php
@props([
'action' => '#',
'method' => 'POST',
'title' => null,
'promptName' => 'prompt',
'promptPlaceholder' => 'Ask the agent to build, fix, or explain something...',
'submitLabel' => 'Send prompt',
'models' => [
'gpt-5.5-medium' => '5.5 Medium',
'gpt-5.5-high' => '5.5 High',
'gpt-5-mini' => '5 Mini',
],
'selectedModel' => 'gpt-5.5-medium',
'approvalModes' => [
'approve-for-me' => 'Approve for me',
'ask-first' => 'Ask first',
'read-only' => 'Read only',
],
'selectedApprovalMode' => 'approve-for-me',
'projects' => [
'dzc' => 'dzc',
'components' => 'components',
'gorge' => 'gorge',
],
'selectedProject' => 'dzc',
'workModes' => [
'local' => 'Work locally',
'cloud' => 'Cloud task',
'review' => 'Review only',
],
'selectedWorkMode' => 'local',
'branches' => [
'main' => 'main',
'develop' => 'develop',
'feature/ai-prompter' => 'feature/ai-prompter',
],
'selectedBranch' => 'main',
'fileName' => 'attachments[]',
'multiple' => true,
'contained' => true,
])
@php
/*
| Prompt composer for AI coding workflows. It keeps the primary textarea
| prominent and exposes model, approval, project, work mode, branch and file
| controls as standard form fields.
*/
$httpMethod = strtoupper($method);
$formMethod = in_array($httpMethod, ['GET', 'POST'], true) ? $httpMethod : 'POST';
$usesMethodSpoofing = ! in_array($httpMethod, ['GET', 'POST'], true);
$footerSelectClass = 'h-9 w-full appearance-none rounded-lg border border-gray-200 bg-white pe-8 ps-9 text-sm font-medium text-gray-700 shadow-sm transition hover:border-gray-300 hover:bg-gray-50 focus:border-brand-500 focus:ring-1 focus:ring-brand-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200 dark:hover:border-gray-600 dark:hover:bg-gray-800';
$approvalModeStyles = [
'approve-for-me' => [
'icon' => 'shield-check',
'iconClass' => 'text-brand-500 dark:text-brand-300',
'selectClass' => 'border-brand-300 focus:border-brand-500 focus:ring-brand-500 dark:border-brand-700',
],
'ask-first' => [
'icon' => 'chat-circle-dots',
'iconClass' => 'text-amber-500 dark:text-amber-400',
'selectClass' => 'border-amber-300 focus:border-amber-500 focus:ring-amber-500 dark:border-amber-700',
],
'read-only' => [
'icon' => 'eye',
'iconClass' => 'text-gray-500 dark:text-gray-400',
'selectClass' => 'border-gray-300 focus:border-gray-500 focus:ring-gray-500 dark:border-gray-600',
],
];
@endphp
<form
method="{{ $formMethod }}"
action="{{ $action }}"
enctype="multipart/form-data"
{{ $attributes->merge(['class' => $contained ? 'mx-auto w-full max-w-4xl' : 'w-full']) }}
>
@if ($usesMethodSpoofing)
@method($httpMethod)
@endif
@if ($formMethod !== 'GET')
@csrf
@endif
@if ($title)
<h2 class="mb-6 text-center text-2xl font-semibold tracking-tight text-gray-900 dark:text-gray-100 sm:text-3xl">
{{ $title }}
</h2>
@endif
<div class="min-w-0 overflow-hidden rounded-2xl border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-900">
<div class="bg-white p-4 dark:bg-gray-900 sm:p-5">
<label for="{{ $promptName }}" class="sr-only">Prompt</label>
<textarea
id="{{ $promptName }}"
name="{{ $promptName }}"
rows="4"
placeholder="{{ $promptPlaceholder }}"
class="block min-h-28 w-full resize-none border-0 bg-transparent p-0 text-base text-gray-900 placeholder-gray-400 shadow-none focus:ring-0 dark:text-gray-100 dark:placeholder-gray-500"
>{{ $slot }}</textarea>
<div class="mt-4 flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
<div class="flex w-full min-w-0 flex-col gap-2 sm:w-auto sm:flex-row sm:flex-wrap sm:items-center">
<label class="inline-flex h-10 w-full shrink-0 cursor-pointer items-center justify-center rounded-lg border border-gray-300 bg-white px-3 text-sm font-medium text-gray-700 shadow-sm transition hover:bg-gray-50 sm:w-auto dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-800">
<x-ui.icon name="plus" size="lg" class="me-2 text-gray-400" />
<span>Attach files</span>
<input type="file" name="{{ $fileName }}" @if ($multiple) multiple @endif class="sr-only">
</label>
<label
class="relative min-w-0 w-full sm:w-auto"
x-data="{
mode: @js($selectedApprovalMode),
styles: @js($approvalModeStyles),
icon() {
return this.styles[this.mode]?.icon ?? 'shield-check';
},
iconClass() {
return this.styles[this.mode]?.iconClass ?? 'text-gray-400 dark:text-gray-500';
},
selectClass() {
return this.styles[this.mode]?.selectClass ?? 'border-gray-300 focus:border-brand-500 focus:ring-brand-500 dark:border-gray-700';
},
}"
>
<span class="sr-only">Approval mode</span>
<i
class="ph pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-base leading-none transition-colors duration-200"
:class="`ph-${icon()} ${iconClass()}`"
aria-hidden="true"
></i>
<select
name="approval_mode"
x-model="mode"
class="h-10 w-full appearance-none rounded-lg border bg-white pe-8 ps-9 text-sm font-medium text-gray-700 shadow-sm transition duration-200 sm:w-auto dark:bg-gray-900 dark:text-gray-200"
:class="selectClass()"
>
@foreach ($approvalModes as $value => $label)
<option value="{{ $value }}" @selected($selectedApprovalMode === $value)>{{ $label }}</option>
@endforeach
</select>
<x-ui.icon name="caret-down" weight="bold" size="sm" class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-gray-400" />
</label>
</div>
<div class="flex w-full min-w-0 items-center gap-2 sm:w-auto sm:justify-end">
<label class="relative min-w-0 flex-1 sm:flex-none">
<span class="sr-only">Model</span>
<select name="model" class="h-10 w-full appearance-none rounded-lg border border-gray-300 bg-white pe-8 ps-3 text-sm font-medium text-gray-700 shadow-sm transition focus:border-brand-500 focus:ring-brand-500 sm:w-auto dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200">
@foreach ($models as $value => $label)
<option value="{{ $value }}" @selected($selectedModel === $value)>{{ $label }}</option>
@endforeach
</select>
<x-ui.icon name="caret-down" weight="bold" size="sm" class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-gray-400" />
</label>
<button type="submit" class="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-lg bg-brand-600 text-white shadow-sm transition-[box-shadow,border-color,color,transform] hover:bg-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 active:bg-brand-700 dark:focus:ring-offset-gray-900" aria-label="{{ $submitLabel }}">
<x-ui.icon name="arrow-up" weight="bold" size="xl" />
</button>
</div>
</div>
</div>
<div class="flex flex-col gap-2 border-t border-gray-200 bg-gray-50 px-4 py-3 dark:border-gray-800 dark:bg-gray-950 sm:flex-row sm:flex-wrap sm:items-center sm:gap-3 sm:px-5">
<label class="relative w-full min-w-0 sm:w-44">
<span class="sr-only">Project</span>
<x-ui.icon name="folder" size="base" class="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<select name="project" class="{{ $footerSelectClass }}">
@foreach ($projects as $value => $label)
<option value="{{ $value }}" @selected($selectedProject === $value)>{{ $label }}</option>
@endforeach
</select>
<x-ui.icon name="caret-down" weight="bold" size="sm" class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-gray-400" />
</label>
<label class="relative w-full min-w-0 sm:w-48">
<span class="sr-only">Work mode</span>
<x-ui.icon name="laptop" size="base" class="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<select name="work_mode" class="{{ $footerSelectClass }}">
@foreach ($workModes as $value => $label)
<option value="{{ $value }}" @selected($selectedWorkMode === $value)>{{ $label }}</option>
@endforeach
</select>
<x-ui.icon name="caret-down" weight="bold" size="sm" class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-gray-400" />
</label>
<label class="relative w-full min-w-0 sm:w-56">
<span class="sr-only">Branch</span>
<x-ui.icon name="git-branch" size="base" class="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<select name="branch" class="{{ $footerSelectClass }}">
@foreach ($branches as $value => $label)
<option value="{{ $value }}" @selected($selectedBranch === $value)>{{ $label }}</option>
@endforeach
</select>
<x-ui.icon name="caret-down" weight="bold" size="sm" class="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-gray-400" />
</label>
</div>
</div>
</form>