nawasara/ui
Nawasara UI provides reusable Blade components, layouts, and shared Livewire concerns for the Nawasara superapp framework—buttons, tables, modals, filters, skeletons, dark mode, workspace navigation, form primitives, plus a WorkspaceManager and reliable browser toast helpers.
Install the Package
composer require nawasara/ui
Ensure your tailwind.config.js includes the package’s Blade files:
content: [
'./resources/**/*.blade.php',
'./vendor/nawasara/*/resources/**/*.blade.php',
],
Publish Assets (if needed) Run:
php artisan vendor:publish --provider="Nawasara\Ui\UiServiceProvider" --tag="public"
(Check the package’s UiServiceProvider for available publishable assets.)
Use a Pre-Built Component
Replace a basic Blade button with the themed button component:
<x-nawasara-ui::button color="primary" size="md">
Save
</x-nawasara-ui::button>
Or integrate a modal:
<x-nawasara-ui::modal id="confirm-delete" title="Delete Item">
<div class="p-4">Are you sure you want to delete this?</div>
<x-slot name="footer">
<x-nawasara-ui::button color="danger" @click="$dispatch('modal-close', { id: 'confirm-delete' })">
Delete
</x-nawasara-ui::button>
</x-slot>
</x-nawasara-ui::modal>
<!-- Trigger modal via Alpine -->
<button @click="$dispatch('modal-open', { id: 'confirm-delete' })">
Delete
</button>
Leverage Livewire Concerns
Add the HasBrowserToast concern to a Livewire component:
use Nawasara\Ui\Livewire\Concerns\HasBrowserToast;
class MyComponent extends Component
{
use HasBrowserToast;
public function save()
{
try {
// Save logic
$this->toastSuccess('Item saved!');
} catch (\Exception $e) {
$this->toastError('Error: ' . $e->getMessage());
}
}
}
<!-- Before -->
<button class="bg-blue-500 text-white px-4 py-2 rounded">
Save
</button>
<!-- After -->
<x-nawasara-ui::button color="primary">
Save
</x-nawasara-ui::button>
color, size, and icon props to maintain consistency without custom CSS.table component and its slots:
<x-nawasara-ui::table>
<x-slot name="title">
Users
</x-slot>
<x-slot name="header">
<th>Name</th>
<th>Email</th>
<th>Actions</th>
</x-slot>
<tbody>
@foreach($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
<td>
<x-nawasara-ui::dropdown-menu-action :resource="$user">
<x-slot name="items">
<x-nawasara-ui::dropdown-menu-action.item href="{{ route('users.edit', $user) }}">
Edit
</x-nawasara-ui::dropdown-menu-action.item>
<x-nawasara-ui::dropdown-menu-action.item
href="#"
@click="$dispatch('modal-open', { id: 'confirm-delete', userId: {{ $user->id }} })">
Delete
</x-nawasara-ui::dropdown-menu-action.item>
</x-slot>
</x-nawasara-ui::dropdown-menu-action>
</td>
</tr>
@endforeach
</tbody>
<x-slot name="footer">
{{ $users->links() }}
</x-slot>
</x-nawasara-ui::table>
// Livewire Component
use Nawasara\Ui\Livewire\Concerns\HasBrowserToast;
class UserManager extends Component
{
use HasBrowserToast;
public function delete($id)
{
User::find($id)->delete();
$this->toastSuccess('User deleted!');
$this->emit('userDeleted');
}
}
<!-- Blade View -->
<x-nawasara-ui::modal-confirm-delete
id="confirm-delete"
title="Delete User"
@deleted="wire.delete({{ $userId }})"
>
Are you sure?
</x-nawasara-ui::modal-confirm-delete>
WorkspaceManager to dynamically build menus:
use Nawasara\Ui\Services\WorkspaceManager;
class Sidebar extends Component
{
public function render()
{
$workspace = app(WorkspaceManager::class)->resolve();
$menu = $workspace->menu()->accessible(auth()->user());
return view('livewire.sidebar', [
'menu' => $menu,
]);
}
}
<!-- Blade View -->
<x-nawasara-ui::workspace-switcher :workspaces="$workspaces" />
<nav>
@foreach($menu as $item)
<x-nawasara-ui::sidebar-item :item="$item" />
@endforeach
</nav>
<x-nawasara-ui::form.input
label="Email"
name="email"
type="email"
:value="old('email', $user->email)"
required
/>
<x-nawasara-ui::form.checkbox
label="Active"
name="active"
:checked="old('active', $user->active)"
/>
tailwind.config.js scans the package’s Blade files:
content: [
'./resources/**/*.blade.php',
'./vendor/nawasara/*/resources/**/*.blade.php',
],
tailwind.config.js:
theme: {
extend: {
colors: {
primary: '#3b82f6', // Override default primary
},
},
},
// Alpine.js
document.addEventListener('modal-open', (e) => {
const modal = document.getElementById(e.detail.id);
modal.showModal();
});
document.addEventListener('modal-close', (e) => {
const modal = document.getElementById(e.detail.id);
modal.close();
});
@can directive:
<x-nawasara-ui::button
color="danger"
@click="$dispatch('modal-open', { id: 'confirm-delete' })"
@can('delete-users')
>
Delete
</x-nawasara-ui::button>
dark-mode-toggle component persists preferences in the session:
<x-nawasara-ui::dark-mode-toggle />
Ensure your Tailwind config includes dark mode:
darkMode: 'class',
@if($users->isEmpty())
<x-nawasara-ui::skeleton-table :rows="5" />
@else
<!-- Actual table -->
@endif
bg-primary-500). Overriding these globally may break components.!important sparingly. Prefer extending the theme in tailwind.config.js:
theme: {
extend: {
colors: {
primary: '#1e40af', // Override Nawasara’s default
},
},
},
modal-open/modal-close events may conflict with custom Livewire events.// Custom namespace
document.addEventListener('nawasara-modal-open',
How can I help you explore Laravel packages today?