Skip to content
Brok UI

Loading…

No results

AI Tools

Open source

AI tool surfaces — text writer, image generator, code generator, an assistant chat, a full-height inbox rail, and a model playground, each with live output panels.

Preview

1 of 7

resources/views/blocks/ai-tools-text.blade.php Blade
@props([
    'model' => 'GPT-4o',
])

<x-ui.section space="xl" {{ $attributes }}>
    <div class="mx-auto max-w-5xl px-4">
        <x-ui.card
            x-data="{
                prompt: '',
                tone: 'professional',
                length: 'medium',
                output: '',
                loading: false,
                timer: null,
                generate() {
                    if (!this.prompt || this.loading) return;
                    this.loading = true;
                    this.output = '';
                    const toneMap = {
                        professional: 'clear and authoritative',
                        friendly: 'warm and conversational',
                        creative: 'imaginative and expressive',
                        formal: 'precise and structured',
                    };
                    const lengthMap = {
                        short: 'one concise sentence',
                        medium: 'two to three sentences',
                        long: 'a full paragraph',
                    };
                    const p = this.prompt;
                    const t = toneMap[this.tone] || 'clear';
                    const l = lengthMap[this.length] || 'two to three sentences';
                    this.timer = setTimeout(() => {
                        this.output = 'Here is ' + l + ' about “' + p + '” written in a ' + t + ' style. The content has been crafted to engage your audience effectively, balancing clarity with impact. Feel free to refine it further to match your exact needs.';
                        this.loading = false;
                    }, 900);
                },
                copy() {
                    if (this.output) navigator.clipboard.writeText(this.output);
                },
                reset() {
                    clearTimeout(this.timer);
                    this.prompt = '';
                    this.output = '';
                    this.loading = false;
                },
                destroy() {
                    clearTimeout(this.timer);
                },
            }"
        >
            <x-ui.card.header class="flex flex-row items-center justify-between gap-4 border-b border-border pb-4">
                <div class="flex items-center gap-2">
                    <svg class="size-5 text-primary" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                        <path d="M12 20h9" stroke-linecap="round" stroke-linejoin="round"/>
                        <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" stroke-linecap="round" stroke-linejoin="round"/>
                    </svg>
                    <span class="text-base font-semibold text-foreground">{{ __('AI Writer') }}</span>
                </div>
                <x-ui.badge variant="secondary">{{ $model }}</x-ui.badge>
            </x-ui.card.header>

            <x-ui.card.content class="pt-6">
                <div class="grid gap-8 lg:grid-cols-2">

                    {{-- LEFT: controls --}}
                    <div class="flex flex-col gap-6">
                        <div class="flex flex-col gap-2">
                            <label for="tg-prompt" class="text-sm font-medium text-foreground">{{ __('Your prompt') }}</label>
                            <x-ui.textarea
                                id="tg-prompt"
                                name="prompt"
                                rows="5"
                                placeholder="{{ __('Describe what you want to write…') }}"
                                x-model="prompt"
                                required
                            />
                        </div>

                        <div class="grid grid-cols-2 gap-4">
                            <div class="flex flex-col gap-2">
                                <label for="tg-tone" class="text-sm font-medium text-foreground">{{ __('Tone') }}</label>
                                <x-ui.select id="tg-tone" name="tone" x-model="tone">
                                    <option value="professional">{{ __('Professional') }}</option>
                                    <option value="friendly">{{ __('Friendly') }}</option>
                                    <option value="creative">{{ __('Creative') }}</option>
                                    <option value="formal">{{ __('Formal') }}</option>
                                </x-ui.select>
                            </div>
                            <div class="flex flex-col gap-2">
                                <label for="tg-length" class="text-sm font-medium text-foreground">{{ __('Length') }}</label>
                                <x-ui.select id="tg-length" name="length" x-model="length">
                                    <option value="short">{{ __('Short') }}</option>
                                    <option value="medium">{{ __('Medium') }}</option>
                                    <option value="long">{{ __('Long') }}</option>
                                </x-ui.select>
                            </div>
                        </div>

                        <x-ui.button
                            x-on:click="generate()"
                            x-bind:disabled="!prompt || loading"
                            x-bind:aria-busy="loading"
                            class="w-full"
                        >
                            <span x-show="loading" class="me-2 inline-flex" aria-hidden="true">
                                <svg class="size-4 animate-spin motion-reduce:animate-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                    <path d="M21 12a9 9 0 1 1-6.219-8.56" stroke-linecap="round"/>
                                </svg>
                            </span>
                            <span x-show="loading">{{ __('Generating…') }}</span>
                            <span x-show="!loading">{{ __('Generate') }}</span>
                        </x-ui.button>
                    </div>

                    {{-- RIGHT: output --}}
                    <div class="flex flex-col gap-4">
                        <div
                            class="relative min-h-[12rem] flex-1 rounded-lg border border-border bg-muted/40 p-6"
                            aria-live="polite"
                            aria-atomic="true"
                            aria-label="{{ __('Generated text output') }}"
                            x-bind:aria-busy="loading"
                        >
                            {{-- Shimmer overlay while loading --}}
                            <div
                                x-show="loading"
                                class="absolute inset-0 flex flex-col gap-4 rounded-lg p-6"
                                aria-hidden="true"
                            >
                                <x-ui.skeleton class="h-3 w-full" />
                                <x-ui.skeleton class="h-3 w-5/6" />
                                <x-ui.skeleton class="h-3 w-4/6" />
                                <x-ui.skeleton class="h-3 w-full" />
                                <x-ui.skeleton class="h-3 w-3/6" />
                            </div>

                            {{-- Empty state --}}
                            <div
                                x-show="!output && !loading"
                                class="flex h-full min-h-[10rem] flex-col items-center justify-center gap-2 text-center"
                            >
                                <svg class="size-8 text-muted-foreground/40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
                                    <path d="M9 12h6m-6 4h6m2 5H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5.586a1 1 0 0 1 .707.293l5.414 5.414a1 1 0 0 1 .293.707V19a2 2 0 0 1-2 2z" stroke-linecap="round" stroke-linejoin="round"/>
                                </svg>
                                <p class="text-sm text-muted-foreground">{{ __('Your generated text will appear here.') }}</p>
                            </div>

                            {{-- Output text --}}
                            <p
                                x-show="output && !loading"
                                x-text="output"
                                class="text-sm leading-relaxed text-foreground"
                            ></p>
                        </div>

                        {{-- Output actions --}}
                        <div class="flex items-center gap-2" x-show="output && !loading">
                            <x-ui.button variant="outline" size="sm" x-on:click="copy()" class="gap-2">
                                <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                                    <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
                                    <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke-linecap="round" stroke-linejoin="round"/>
                                </svg>
                                {{ __('Copy') }}
                            </x-ui.button>
                            <x-ui.button variant="ghost" size="sm" x-on:click="generate()" class="gap-2">
                                <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                                    <path d="M1 4v6h6" stroke-linecap="round" stroke-linejoin="round"/>
                                    <path d="M3.51 15a9 9 0 1 0 .49-3.95" stroke-linecap="round" stroke-linejoin="round"/>
                                </svg>
                                {{ __('Regenerate') }}
                            </x-ui.button>
                            <x-ui.button variant="ghost" size="sm" x-on:click="reset()" class="ms-auto gap-2 text-muted-foreground">
                                <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                                    <path d="M18 6 6 18M6 6l12 12" stroke-linecap="round" stroke-linejoin="round"/>
                                </svg>
                                {{ __('Clear') }}
                            </x-ui.button>
                        </div>
                    </div>

                </div>
            </x-ui.card.content>
        </x-ui.card>
    </div>
</x-ui.section>

Installation

terminal
php artisan ui:add blocks/ai-tools-text

Registry contract

Install confidence

php artisan ui:add blocks/ai-tools-text writes only the generated targets below. The CLI validates each file hash before writing and prompts before replacing local changes unless --force is used.

Version
1.1.5
License
open
Stability
stable
Contract
v1
Foundation
≥ 1.0.0
Type Generated target
blade resources/views/blocks/ai-tools-text.blade.php

Registry dependencies

badge button card section select textarea skeleton

Package dependencies

composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: what the block is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this block in an assistant.

ai-tools-text.md
# Brok UI block: Text Generator (`ai-tools-text`)

Interactive AI writing tool with tone and length controls, a live output panel, and copy/regenerate actions.

Brok UI is a Laravel Blade registry. `ui:add` copies this block into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.

## Install

```bash
php artisan ui:add blocks/ai-tools-text
```

## Render it

```blade
<x-blocks.ai-tools-text />
```

## Props

- `model` (string, default `GPT-4o`)

## Use when

- Demoing an AI writing tool where a visitor types a prompt, picks a tone and length, and reads generated copy in a live output panel.
- Showing copy and regenerate actions on AI-produced text inside a single card.

## Avoid when

- Use ai-tools-image for an image-generation demo or ai-tools-code for a code-generation demo; ai-tools-text is text-only.

## Rules

- Render the installed block with `<x-blocks.ai-tools-text />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.

## Links

- Docs: https://brokui.dev/blocks/ai-tools-text
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/ai-tools-text.json

Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.

Guidance

Use when

  • Demoing an AI writing tool where a visitor types a prompt, picks a tone and length, and reads generated copy in a live output panel.
  • Showing copy and regenerate actions on AI-produced text inside a single card.

Avoid when

  • Use ai-tools-image for an image-generation demo or ai-tools-code for a code-generation demo; ai-tools-text is text-only.

Anti-patterns

  • Do not replace semantic props with conflicting utility classes.
  • Do not remove labels, focus styles, or state attributes.

Usage

Render the block as a component, passing data where useful:

resources/views/welcome.blade.php Blade
<x-blocks.ai-tools-text />

Built from primitives

Composes <brok:*> Semantic tokens Re-themeable RTL-ready

This block composes installed <brok:*> primitives and semantic design tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by editing CSS variables; flip the preview to RTL to confirm it mirrors.

Source

The exact, editable file ui:add writes into your app. The preview above renders this same source — there are no preview-only blocks.

resources/views/blocks/ai-tools-text.blade.php Blade
@props([
    'model' => 'GPT-4o',
])

<x-ui.section space="xl" {{ $attributes }}>
    <div class="mx-auto max-w-5xl px-4">
        <x-ui.card
            x-data="{
                prompt: '',
                tone: 'professional',
                length: 'medium',
                output: '',
                loading: false,
                timer: null,
                generate() {
                    if (!this.prompt || this.loading) return;
                    this.loading = true;
                    this.output = '';
                    const toneMap = {
                        professional: 'clear and authoritative',
                        friendly: 'warm and conversational',
                        creative: 'imaginative and expressive',
                        formal: 'precise and structured',
                    };
                    const lengthMap = {
                        short: 'one concise sentence',
                        medium: 'two to three sentences',
                        long: 'a full paragraph',
                    };
                    const p = this.prompt;
                    const t = toneMap[this.tone] || 'clear';
                    const l = lengthMap[this.length] || 'two to three sentences';
                    this.timer = setTimeout(() => {
                        this.output = 'Here is ' + l + ' about “' + p + '” written in a ' + t + ' style. The content has been crafted to engage your audience effectively, balancing clarity with impact. Feel free to refine it further to match your exact needs.';
                        this.loading = false;
                    }, 900);
                },
                copy() {
                    if (this.output) navigator.clipboard.writeText(this.output);
                },
                reset() {
                    clearTimeout(this.timer);
                    this.prompt = '';
                    this.output = '';
                    this.loading = false;
                },
                destroy() {
                    clearTimeout(this.timer);
                },
            }"
        >
            <x-ui.card.header class="flex flex-row items-center justify-between gap-4 border-b border-border pb-4">
                <div class="flex items-center gap-2">
                    <svg class="size-5 text-primary" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                        <path d="M12 20h9" stroke-linecap="round" stroke-linejoin="round"/>
                        <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" stroke-linecap="round" stroke-linejoin="round"/>
                    </svg>
                    <span class="text-base font-semibold text-foreground">{{ __('AI Writer') }}</span>
                </div>
                <x-ui.badge variant="secondary">{{ $model }}</x-ui.badge>
            </x-ui.card.header>

            <x-ui.card.content class="pt-6">
                <div class="grid gap-8 lg:grid-cols-2">

                    {{-- LEFT: controls --}}
                    <div class="flex flex-col gap-6">
                        <div class="flex flex-col gap-2">
                            <label for="tg-prompt" class="text-sm font-medium text-foreground">{{ __('Your prompt') }}</label>
                            <x-ui.textarea
                                id="tg-prompt"
                                name="prompt"
                                rows="5"
                                placeholder="{{ __('Describe what you want to write…') }}"
                                x-model="prompt"
                                required
                            />
                        </div>

                        <div class="grid grid-cols-2 gap-4">
                            <div class="flex flex-col gap-2">
                                <label for="tg-tone" class="text-sm font-medium text-foreground">{{ __('Tone') }}</label>
                                <x-ui.select id="tg-tone" name="tone" x-model="tone">
                                    <option value="professional">{{ __('Professional') }}</option>
                                    <option value="friendly">{{ __('Friendly') }}</option>
                                    <option value="creative">{{ __('Creative') }}</option>
                                    <option value="formal">{{ __('Formal') }}</option>
                                </x-ui.select>
                            </div>
                            <div class="flex flex-col gap-2">
                                <label for="tg-length" class="text-sm font-medium text-foreground">{{ __('Length') }}</label>
                                <x-ui.select id="tg-length" name="length" x-model="length">
                                    <option value="short">{{ __('Short') }}</option>
                                    <option value="medium">{{ __('Medium') }}</option>
                                    <option value="long">{{ __('Long') }}</option>
                                </x-ui.select>
                            </div>
                        </div>

                        <x-ui.button
                            x-on:click="generate()"
                            x-bind:disabled="!prompt || loading"
                            x-bind:aria-busy="loading"
                            class="w-full"
                        >
                            <span x-show="loading" class="me-2 inline-flex" aria-hidden="true">
                                <svg class="size-4 animate-spin motion-reduce:animate-none" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                    <path d="M21 12a9 9 0 1 1-6.219-8.56" stroke-linecap="round"/>
                                </svg>
                            </span>
                            <span x-show="loading">{{ __('Generating…') }}</span>
                            <span x-show="!loading">{{ __('Generate') }}</span>
                        </x-ui.button>
                    </div>

                    {{-- RIGHT: output --}}
                    <div class="flex flex-col gap-4">
                        <div
                            class="relative min-h-[12rem] flex-1 rounded-lg border border-border bg-muted/40 p-6"
                            aria-live="polite"
                            aria-atomic="true"
                            aria-label="{{ __('Generated text output') }}"
                            x-bind:aria-busy="loading"
                        >
                            {{-- Shimmer overlay while loading --}}
                            <div
                                x-show="loading"
                                class="absolute inset-0 flex flex-col gap-4 rounded-lg p-6"
                                aria-hidden="true"
                            >
                                <x-ui.skeleton class="h-3 w-full" />
                                <x-ui.skeleton class="h-3 w-5/6" />
                                <x-ui.skeleton class="h-3 w-4/6" />
                                <x-ui.skeleton class="h-3 w-full" />
                                <x-ui.skeleton class="h-3 w-3/6" />
                            </div>

                            {{-- Empty state --}}
                            <div
                                x-show="!output && !loading"
                                class="flex h-full min-h-[10rem] flex-col items-center justify-center gap-2 text-center"
                            >
                                <svg class="size-8 text-muted-foreground/40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
                                    <path d="M9 12h6m-6 4h6m2 5H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5.586a1 1 0 0 1 .707.293l5.414 5.414a1 1 0 0 1 .293.707V19a2 2 0 0 1-2 2z" stroke-linecap="round" stroke-linejoin="round"/>
                                </svg>
                                <p class="text-sm text-muted-foreground">{{ __('Your generated text will appear here.') }}</p>
                            </div>

                            {{-- Output text --}}
                            <p
                                x-show="output && !loading"
                                x-text="output"
                                class="text-sm leading-relaxed text-foreground"
                            ></p>
                        </div>

                        {{-- Output actions --}}
                        <div class="flex items-center gap-2" x-show="output && !loading">
                            <x-ui.button variant="outline" size="sm" x-on:click="copy()" class="gap-2">
                                <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                                    <rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
                                    <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke-linecap="round" stroke-linejoin="round"/>
                                </svg>
                                {{ __('Copy') }}
                            </x-ui.button>
                            <x-ui.button variant="ghost" size="sm" x-on:click="generate()" class="gap-2">
                                <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                                    <path d="M1 4v6h6" stroke-linecap="round" stroke-linejoin="round"/>
                                    <path d="M3.51 15a9 9 0 1 0 .49-3.95" stroke-linecap="round" stroke-linejoin="round"/>
                                </svg>
                                {{ __('Regenerate') }}
                            </x-ui.button>
                            <x-ui.button variant="ghost" size="sm" x-on:click="reset()" class="ms-auto gap-2 text-muted-foreground">
                                <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                                    <path d="M18 6 6 18M6 6l12 12" stroke-linecap="round" stroke-linejoin="round"/>
                                </svg>
                                {{ __('Clear') }}
                            </x-ui.button>
                        </div>
                    </div>

                </div>
            </x-ui.card.content>
        </x-ui.card>
    </div>
</x-ui.section>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.1.5
Status
Stable
License
open
Deprecation
Not deprecated
Contract
v1
Foundation
≥ 1.0.0