Invoke when styling buttons, showing toast alerts, adding a loading state or spinner, or building forms, file inputs and navigation in a Nyumbani app. Covers btn classes, back()->alert(), <x-nyumbani::loader>, file-input and nav components.
php artisan boost:add-skill nyumbani/ui
Save this content to: .claude/skills/nyumbani-ui-theme/SKILL.md
# Nyumbani UI Theme
## Buttons
Every button is primary. Use `btn btn-primary`, with `btn-sm` or `btn-lg` for size. There is no danger or outline variant, and `btn-secondary` renders the same as primary. Never choose a color per button. A destructive action is still a primary button guarded by native `confirm()`.
## Toasts
Flash with the `alert` macro and let the layout show it:
```php
return back()->alert('success', trans('alerts.customers.saved', ['name' => $customer->name]));
```
Every toast type (success, error, info, warning) renders in the one success color. The type still sets the icon and screen-reader meaning, so pass the honest type: `success` when it did what was asked, `error` when it failed and nothing changed, `warning` when it worked but needs another look, `info` for something to know. Put the text in `lang/alerts.php` as full sentences with `:placeholder` values. `redirect()->alert(...)` with no route goes back, like `back()->alert(...)`, and a Laravel `status` flash also shows as a success toast. From JavaScript, call `toastr.success('...')`.
## Loader
```blade
<x-nyumbani::loader />
<x-nyumbani::loader size="md" message="Nyumbani is loading this for you..." />
<x-nyumbani::loader message="" />
```
Props: `message` (default "Nyumbani is processing your data...") and `size` (`sm`, `md`, `lg`). Pass `message=""` to hide the text, because `null` falls back to the default. It is the animated Nyumbani mark, served from the package. Use it for any wait the user can see, and do not invent another spinner.
## Components
- `<x-nyumbani::modal>`: see the nyumbani-modal skill.
- `<x-nyumbani::period-picker>`: the date, month, year and range filter for reports and lists; see the nyumbani-period-picker skill.
- Form controls are 16px on phones and 14px from `sm` up, and the layout's viewport is `width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no`, so pages do not zoom on focus or on a pinch. Never add `text-sm` or `text-xs` to an input, select or textarea, and keep that viewport meta when you write your own base layout.
- `<x-nyumbani::file-input name="..." label="..." accept="..." :current="$upload" />`, where `$upload` is the saved Upload model (it supplies `url`, `title`, `formattedSize` and `isImage()`). The form needs `enctype="multipart/form-data"`.
- `<x-nyumbani::nav-group>` and `<x-nyumbani::nav-link>` build the sidebar. Implement the `HasHomeRoute` contract for the home link.
- Every top-level `nav-link` and `nav-group` needs an icon: put the `<path>` elements of a 24x24 outline Heroicon (Outline set, Copy SVG, paths only, never the `<svg>`) in the link's slot, or in `<x-slot:icon>` of a group. Links inside a group use `sub` and take no icon. The component draws the svg with stroke width 2.
## Rules
- Components that need logic are classes in `Nyumbani\Ui\Views\Components`, registered under the `nyumbani` namespace. Simple ones are anonymous Blade components.
- No `@php` in views. Prepare data in a controller or component class.
- Use `@use` for every class a view references.
- After adding Tailwind classes in a package view, run `npm run build` in the app.
## Placeholders
Every form input has a `placeholder`, never just the label: a prompt (`Enter your name here`), an example (`e.g. Jane Wanjiru`) or the rule (`At least 8 characters`). A `<select>` gets an empty first option as its placeholder. Checkbox, radio, file, hidden, date, time and colour inputs are exempt. Translate placeholders and never write a currency in one.
Every button is primary. Use btn btn-primary, with btn-sm or btn-lg for size. There is no danger or outline variant, and btn-secondary renders the same as primary. Never choose a color per button. A destructive action is still a primary button guarded by native confirm().
Flash with the alert macro and let the layout show it:
return back()->alert('success', trans('alerts.customers.saved', ['name' => $customer->name]));
Every toast type (success, error, info, warning) renders in the one success color. The type still sets the icon and screen-reader meaning, so pass the honest type: success when it did what was asked, error when it failed and nothing changed, warning when it worked but needs another look, info for something to know. Put the text in lang/alerts.php as full sentences with :placeholder values. redirect()->alert(...) with no route goes back, like back()->alert(...), and a Laravel status flash also shows as a success toast. From JavaScript, call toastr.success('...').
<x-nyumbani::loader />
<x-nyumbani::loader size="md" message="Nyumbani is loading this for you..." />
<x-nyumbani::loader message="" />
Props: message (default "Nyumbani is processing your data...") and size (sm, md, lg). Pass message="" to hide the text, because null falls back to the default. It is the animated Nyumbani mark, served from the package. Use it for any wait the user can see, and do not invent another spinner.
<x-nyumbani::modal>: see the nyumbani-modal skill.<x-nyumbani::period-picker>: the date, month, year and range filter for reports and lists; see the nyumbani-period-picker skill.sm up, and the layout's viewport is width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, so pages do not zoom on focus or on a pinch. Never add text-sm or text-xs to an input, select or textarea, and keep that viewport meta when you write your own base layout.<x-nyumbani::file-input name="..." label="..." accept="..." :current="$upload" />, where $upload is the saved Upload model (it supplies url, title, formattedSize and isImage()). The form needs enctype="multipart/form-data".<x-nyumbani::nav-group> and <x-nyumbani::nav-link> build the sidebar. Implement the HasHomeRoute contract for the home link.nav-link and nav-group needs an icon: put the <path> elements of a 24x24 outline Heroicon (Outline set, Copy SVG, paths only, never the <svg>) in the link's slot, or in <x-slot:icon> of a group. Links inside a group use sub and take no icon. The component draws the svg with stroke width 2.Nyumbani\Ui\Views\Components, registered under the nyumbani namespace. Simple ones are anonymous Blade components.@php in views. Prepare data in a controller or component class.@use for every class a view references.npm run build in the app.Every form input has a placeholder, never just the label: a prompt (Enter your name here), an example (e.g. Jane Wanjiru) or the rule (At least 8 characters). A <select> gets an empty first option as its placeholder. Checkbox, radio, file, hidden, date, time and colour inputs are exempt. Translate placeholders and never write a currency in one.
How can I help you explore Laravel packages today?