├── composer.json ├── config └── laravel-bootstrap-components.php ├── readme.md ├── resources └── views │ └── components │ ├── alert.blade.php │ ├── badge.blade.php │ ├── button.blade.php │ ├── check-label.blade.php │ ├── check.blade.php │ ├── close.blade.php │ ├── color.blade.php │ ├── datalist.blade.php │ ├── desc.blade.php │ ├── dropdown-item.blade.php │ ├── dropdown.blade.php │ ├── error.blade.php │ ├── form.blade.php │ ├── help.blade.php │ ├── icon.blade.php │ ├── image.blade.php │ ├── input-addon.blade.php │ ├── input.blade.php │ ├── label.blade.php │ ├── link.blade.php │ ├── nav-dropdown.blade.php │ ├── nav-link.blade.php │ ├── pagination.blade.php │ ├── progress.blade.php │ ├── radio.blade.php │ ├── select.blade.php │ └── textarea.blade.php └── src ├── Providers └── LaravelBootstrapComponentsProvider.php └── Traits └── WithModel.php /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bastinald/laravel-bootstrap-components", 3 | "homepage": "https://github.com/bastinald/laravel-bootstrap-components", 4 | "description": "Laravel Bootstrap Blade components.", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Kevin Dion", 9 | "email": "bastinald@icloud.com", 10 | "role": "Developer" 11 | } 12 | ], 13 | "require": { 14 | "laravel/framework": "^8.0" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "Bastinald\\LaravelBootstrapComponents\\": "src" 19 | } 20 | }, 21 | "extra": { 22 | "laravel": { 23 | "providers": [ 24 | "Bastinald\\LaravelBootstrapComponents\\Providers\\LaravelBootstrapComponentsProvider" 25 | ] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /config/laravel-bootstrap-components.php: -------------------------------------------------------------------------------- 1 | 'solid', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Use With Model Trait 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This value specifies if you are using the WithModel trait for modelled 26 | | form data in your Livewire components. This trait allows you to use a 27 | | single $model property for form data, rather than a ton of separate ones. 28 | | 29 | */ 30 | 31 | 'use_with_model_trait' => true, 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Laravel Bootstrap Components 2 | 3 | This package contains a set of useful Bootstrap Laravel Blade components. It promotes DRY principles and allows you to keep your HTML nice and clean. Components include alerts, badges, buttons, form inputs (with automatic error feedback), dropdowns, navs, pagination (responsive), and more. The components come with Laravel Livewire integration built in, so you can use them with or without Livewire. 4 | 5 | ## Documentation 6 | 7 | - [Requirements](#requirements) 8 | - [Installation](#installation) 9 | - [Components](#components) 10 | - [Alert](#alert) 11 | - [Badge](#badge) 12 | - [Button](#button) 13 | - [Check](#check) 14 | - [Close](#close) 15 | - [Color](#color) 16 | - [Datalist](#datalist) 17 | - [Dropdown](#dropdown) 18 | - [Dropdown Item](#dropdown-item) 19 | - [Icon](#icon) 20 | - [Image](#image) 21 | - [Input](#input) 22 | - [Link](#link) 23 | - [Nav Dropdown](#nav-dropdown) 24 | - [Nav Link](#nav-link) 25 | - [Pagination](#pagination) 26 | - [Progress](#progress) 27 | - [Radio](#radio) 28 | - [Select](#select) 29 | - [Textarea](#textarea) 30 | - [Traits](#traits) 31 | - [WithModel](#withmodel) 32 | - [Publishing Assets](#publishing-assets) 33 | - [Custom Views](#custom-views) 34 | - [Custom Icons](#custom-icons) 35 | 36 | ## Requirements 37 | 38 | - Bootstrap 5 must be installed via webpack first 39 | - Font Awesome must be installed to use icons 40 | 41 | ## Installation 42 | 43 | Require the package via composer: 44 | 45 | ```console 46 | composer require bastinald/laravel-bootstrap-components 47 | ``` 48 | 49 | ## Components 50 | 51 | ### Alert 52 | 53 | A Bootstrap alert: 54 | 55 | ```html 56 | 61 | ``` 62 | 63 | #### Available Props & Slots 64 | 65 | - `icon`: Font Awesome icon to show before label e.g. `cog`, `envelope` 66 | - `label`: label to display, can also be placed in the `slot` 67 | - `color`: Bootstrap color e.g. `primary`, `danger`, `success` 68 | - `dismissible`: set the alert to be dismissible 69 | 70 | --- 71 | 72 | ### Badge 73 | 74 | A Bootstrap badge: 75 | 76 | ```html 77 | 81 | ``` 82 | 83 | #### Available Props & Slots 84 | 85 | - `icon`: Font Awesome icon to show before label e.g. `cog`, `envelope` 86 | - `label`: label to display, can also be placed in the `slot` 87 | - `color`: Bootstrap color e.g. `primary`, `danger`, `success` 88 | 89 | --- 90 | 91 | ### Button 92 | 93 | A Bootstrap button: 94 | 95 | ```html 96 | 102 | ``` 103 | 104 | #### Available Props & Slots 105 | 106 | - `icon`: Font Awesome icon to show before label e.g. `cog`, `envelope` 107 | - `label`: label to display, can also be placed in the `slot` 108 | - `color`: Bootstrap color e.g. `primary`, `danger`, `success` 109 | - `size`: Bootstrap button size e.g. `sm`, `lg` 110 | - `type`: button type e.g. `button`, `submit` 111 | - `route`: sets the `href` to a route 112 | - `url`: sets the `href` to a url 113 | - `href`: sets the `href` 114 | - `dismiss`: a `data-bs-dismiss` value e.g. `alert`, `modal` 115 | - `toggle`: a `data-bs-toggle` value e.g. `collapse`, `dropdown` 116 | - `click`: Livewire action on click 117 | - `confirm`: prompts the user for confirmation on click 118 | 119 | --- 120 | 121 | ### Check 122 | 123 | A Bootstrap checkbox input: 124 | 125 | ```html 126 | 133 | ``` 134 | 135 | #### Available Props & Slots 136 | 137 | - `label`: label to display above the input 138 | - `checkLabel`: label to display beside the input 139 | - `help`: helper label to display under the input 140 | - `switch`: style the input as a switch 141 | - `model`: Livewire model property key 142 | - `lazy`: bind Livewire data on change 143 | 144 | --- 145 | 146 | ### Close 147 | 148 | A Bootstrap close button: 149 | 150 | ```html 151 | 154 | ``` 155 | 156 | #### Available Props & Slots 157 | 158 | - `color`: Bootstrap close color e.g. `white` 159 | - `dismiss`: a `data-bs-dismiss` value e.g. `alert`, `modal` 160 | 161 | --- 162 | 163 | ### Color 164 | 165 | A Bootstrap color picker input: 166 | 167 | ```html 168 | 175 | ``` 176 | 177 | #### Available Props & Slots 178 | 179 | - `label`: label to display above the input 180 | - `icon`: Font Awesome icon to show before input e.g. `cog`, `envelope` 181 | - `prepend`: addon to display before input, can be used via named slot 182 | - `append`: addon to display after input, can be used via named slot 183 | - `size`: Bootstrap input size e.g. `sm`, `lg` 184 | - `help`: helper label to display under the input 185 | - `model`: Livewire model property key 186 | - `lazy`: bind Livewire data on change 187 | 188 | --- 189 | 190 | ### Datalist 191 | 192 | A Bootstrap datalist input: 193 | 194 | ```html 195 | 203 | ``` 204 | 205 | #### Available Props & Slots 206 | 207 | - `label`: label to display above the input 208 | - `options`: array of input options e.g. `['Red', 'Blue']` 209 | - `icon`: Font Awesome icon to show before input e.g. `cog`, `envelope` 210 | - `prepend`: addon to display before input, can be used via named slot 211 | - `append`: addon to display after input, can be used via named slot 212 | - `size`: Bootstrap input size e.g. `sm`, `lg` 213 | - `help`: helper label to display under the input 214 | - `model`: Livewire model property key 215 | - `debounce`: time in ms to bind Livewire data on keyup e.g. `500` 216 | - `lazy`: bind Livewire data on change 217 | 218 | --- 219 | 220 | ### Desc 221 | 222 | A description list: 223 | 224 | ```html 225 | 229 | ``` 230 | 231 | #### Available Props & Slots 232 | 233 | - `tern`: the description list term 234 | - `details`: the description list details, can also be placed in the `slot` 235 | - `date`: date to use instead of details (for use with [Laravel Timezone](https://github.com/jamesmills/laravel-timezone)) 236 | 237 | --- 238 | 239 | ### Dropdown 240 | 241 | A Bootstrap dropdown: 242 | 243 | ```html 244 | 248 | 252 | 256 | 257 | ``` 258 | 259 | #### Available Props & Slots 260 | 261 | - `icon`: Font Awesome icon to show before label e.g. `cog`, `envelope` 262 | - `label`: dropdown label to display, can be used via named slot 263 | - `items`: dropdown items, can also be placed in the `slot` 264 | - `color`: Bootstrap color e.g. `primary`, `danger`, `success` 265 | - `size`: Bootstrap button size e.g. `sm`, `lg` 266 | 267 | --- 268 | 269 | ### Dropdown Item 270 | 271 | A Bootstrap dropdown menu item: 272 | 273 | ```html 274 | 278 | ``` 279 | 280 | #### Available Props & Slots 281 | 282 | - `icon`: Font Awesome icon to show before label e.g. `cog`, `envelope` 283 | - `label`: label to display, can also be placed in the `slot` 284 | - `route`: sets the `href` to a route 285 | - `url`: sets the `href` to a url 286 | - `href`: sets the `href` 287 | 288 | --- 289 | 290 | ### Form 291 | 292 | A Bootstrap form: 293 | 294 | ```html 295 | 296 | 297 | 298 | 299 | 300 | ``` 301 | 302 | #### Available Props & Slots 303 | 304 | - `submit`: Livewire action on submit 305 | 306 | ### Icon 307 | 308 | A Font Awesome icon: 309 | 310 | ```html 311 | 314 | ``` 315 | 316 | #### Available Props & Slots 317 | 318 | - `name`: Font Awesome icon name e.g. `cog`, `rocket` 319 | - `style`: Font Awesome icon style e.g. `solid`, `regular`, `brands` 320 | - `size`: Font Awesome icon size e.g. `sm`, `lg`, `3x`, `5x` 321 | - `color`: Bootstrap color e.g. `primary`, `danger`, `success` 322 | - `spin`: sets the icon to use a spin animation 323 | - `pulse`: sets the icon to use a pulse animation 324 | 325 | --- 326 | 327 | ### Image 328 | 329 | An image: 330 | 331 | ```html 332 | 337 | ``` 338 | 339 | #### Available Props & Slots 340 | 341 | - `asset`: sets the `src` to an asset 342 | - `src`: sets the `src` 343 | - `fluid`: sets the image to be fluid width 344 | - `thumbnail`: sets the image to use thumbnail styling 345 | - `rounded`: sets the image to have rounded corners 346 | 347 | --- 348 | 349 | ### Input 350 | 351 | A Bootstrap text input: 352 | 353 | ```html 354 | 360 | 361 | 362 | 363 | 364 | ``` 365 | 366 | #### Available Props & Slots 367 | 368 | - `label`: label to display above the input 369 | - `type`: input type e.g. `text`, `email` 370 | - `icon`: Font Awesome icon to show before input e.g. `cog`, `envelope` 371 | - `prepend`: addon to display before input, can be used via named slot 372 | - `append`: addon to display after input, can be used via named slot 373 | - `size`: Bootstrap input size e.g. `sm`, `lg` 374 | - `help`: helper label to display under the input 375 | - `model`: Livewire model property key 376 | - `debounce`: time in ms to bind Livewire data on keyup e.g. `500` 377 | - `lazy`: bind Livewire data on change 378 | 379 | --- 380 | 381 | ### Link 382 | 383 | A hyperlink: 384 | 385 | ```html 386 | 390 | ``` 391 | 392 | #### Available Props & Slots 393 | 394 | - `icon`: Font Awesome icon to show before label e.g. `cog`, `envelope` 395 | - `label`: label to display, can also be placed in the `slot` 396 | - `route`: sets the `href` to a route 397 | - `url`: sets the `href` to a url 398 | - `href`: sets the `href` 399 | 400 | --- 401 | 402 | ### Nav Dropdown 403 | 404 | A Bootstrap nav dropdown: 405 | 406 | ```html 407 | 410 | 414 | 418 | 419 | ``` 420 | 421 | #### Available Props & Slots 422 | 423 | - `icon`: Font Awesome icon to show before label e.g. `cog`, `envelope` 424 | - `label`: dropdown label to display, can be used via named slot 425 | - `items`: dropdown items, can also be placed in the `slot` 426 | 427 | --- 428 | 429 | ### Nav Link 430 | 431 | A Bootstrap nav link: 432 | 433 | ```html 434 | 438 | ``` 439 | 440 | #### Available Props & Slots 441 | 442 | - `icon`: Font Awesome icon to show before label e.g. `cog`, `envelope` 443 | - `label`: label to display, can also be placed in the `slot` 444 | - `route`: sets the `href` to a route 445 | - `url`: sets the `href` to a url 446 | - `href`: sets the `href` 447 | 448 | --- 449 | 450 | ### Pagination 451 | 452 | Responsive Bootstrap pagination links: 453 | 454 | ```html 455 | 459 | ``` 460 | 461 | #### Available Props & Slots 462 | 463 | - `links`: paginated Laravel models 464 | - `justify`: Bootstrap justification e.g. `start`, `end` 465 | 466 | --- 467 | 468 | ### Progress 469 | 470 | A Bootstrap progress bar: 471 | 472 | ```html 473 | 481 | ``` 482 | 483 | #### Available Props & Slots 484 | 485 | - `label`: label to display inside the progress bar 486 | - `percent`: percentage of the progress bar 487 | - `color`: Bootstrap color e.g. `primary`, `danger`, `success` 488 | - `height`: height of the progress bar in pixels 489 | - `animated`: animate the progress bar 490 | - `striped`: use striped styling for the progress bar 491 | 492 | --- 493 | 494 | ### Radio 495 | 496 | A Bootstrap radio input: 497 | 498 | ```html 499 | 506 | ``` 507 | 508 | #### Available Props & Slots 509 | 510 | - `label`: label to display above the input 511 | - `options`: array of input options e.g. `['Red', 'Blue']` 512 | - `help`: helper label to display under the input 513 | - `switch`: sets the input to use a switch style 514 | - `model`: Livewire model property key 515 | - `lazy`: bind Livewire data on change 516 | 517 | --- 518 | 519 | ### Select 520 | 521 | A Bootstrap select input: 522 | 523 | ```html 524 | 533 | ``` 534 | 535 | #### Available Props & Slots 536 | 537 | - `label`: label to display above the input 538 | - `placeholder`: placeholder to use for the empty first option 539 | - `options`: array of input options e.g. `['Red', 'Blue']` 540 | - `icon`: Font Awesome icon to show before input e.g. `cog`, `envelope` 541 | - `prepend`: addon to display before input, can be used via named slot 542 | - `append`: addon to display after input, can be used via named slot 543 | - `size`: Bootstrap input size e.g. `sm`, `lg` 544 | - `help`: helper label to display under the input 545 | - `model`: Livewire model property key 546 | - `lazy`: bind Livewire data on change 547 | 548 | --- 549 | 550 | ### Textarea 551 | 552 | A Bootstrap textarea input: 553 | 554 | ```html 555 | 561 | ``` 562 | 563 | #### Available Props & Slots 564 | 565 | - `label`: label to display above the input 566 | - `icon`: Font Awesome icon to show before input e.g. `cog`, `envelope` 567 | - `prepend`: addon to display before input, can be used via named slot 568 | - `append`: addon to display after input, can be used via named slot 569 | - `size`: Bootstrap input size e.g. `sm`, `lg` 570 | - `help`: helper label to display under the input 571 | - `model`: Livewire model property key 572 | - `debounce`: time in ms to bind Livewire data on keyup e.g. `500` 573 | - `lazy`: bind Livewire data on change 574 | 575 | ## Traits 576 | 577 | ### WithModel 578 | 579 | This trait makes form data model manipulation a breeze. No more having to create a Livewire component property for every single form input. All form data will be placed inside the `$model` property array. 580 | 581 | #### Getting Model Data 582 | 583 | Get the model data as a collection: 584 | 585 | ```php 586 | $collection = $this->model(); 587 | ``` 588 | 589 | #### Setting Model Data 590 | 591 | Set a single value: 592 | 593 | ```php 594 | $this->setModel('name', 'Kevin'); 595 | ``` 596 | 597 | Set values using Eloquent model data: 598 | 599 | ```php 600 | $this->setModel(User::first()); 601 | ``` 602 | 603 | Set values using an array: 604 | 605 | ```php 606 | $this->setModel([ 607 | 'name' => 'Kevin', 608 | 'email' => 'kevin@example.com', 609 | ]); 610 | ``` 611 | 612 | #### Working With Arrays 613 | 614 | Add an empty array item: 615 | 616 | ```php 617 | $this->addModelItem('locations'); 618 | ``` 619 | 620 | Remove an array item by its key: 621 | 622 | ```php 623 | $this->removeModelItem('locations', 3); 624 | ``` 625 | 626 | Order an array item by its key & direction: 627 | 628 | ```php 629 | $this->orderModelItem('locations', 3, 'up'); 630 | ``` 631 | 632 | The direction should be `up` or `down`. 633 | 634 | #### Binding Model Data 635 | 636 | Package components work with this trait via the `model` attribute: 637 | 638 | ```html 639 | 640 | 641 | ``` 642 | 643 | #### Validating Model Data 644 | 645 | Use the `validateModel` method to validate model data: 646 | 647 | ```php 648 | $this->validateModel([ 649 | 'name' => ['required'], 650 | 'email' => ['required', 'email'], 651 | ]); 652 | ``` 653 | 654 | This method works just like the Livewire `validate` method, so you can specify your rules in a separate `rules` method if you prefer. 655 | 656 | ## Publishing Assets 657 | 658 | ### Custom Views 659 | 660 | Use your own component views by publishing the package views: 661 | 662 | ```console 663 | php artisan vendor:publish --tag=laravel-bootstrap-components:views 664 | ``` 665 | 666 | Now edit the files inside `resources/views/vendor/bs`. The package will use these files to render the components. 667 | 668 | ### Custom Icons 669 | 670 | Use your own font icons by publishing the package config: 671 | 672 | ```console 673 | php artisan vendor:publish --tag=laravel-bootstrap-components:config 674 | ``` 675 | 676 | Now edit the `icon_class_prefix` value inside `config/laravel-bootstrap-components.php`. The package will use this class to render the icons. 677 | -------------------------------------------------------------------------------- /resources/views/components/alert.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | 'color' => 'success', 5 | 'dismissible' => false, 6 | ]) 7 | 8 | @php 9 | $attributes = $attributes->class([ 10 | 'alert alert-' . $color . ' fade show mb-0', 11 | 'alert-dismissible' => $dismissible, 12 | ])->merge([ 13 | // 14 | ]); 15 | @endphp 16 | 17 |
18 | 19 | 20 | {{ $label ?? $slot }} 21 | 22 | @if($dismissible) 23 | 24 | @endif 25 |
26 | -------------------------------------------------------------------------------- /resources/views/components/badge.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | 'color' => 'primary', 5 | ]) 6 | 7 | @php 8 | $attributes = $attributes->class([ 9 | 'badge bg-' . $color, 10 | ])->merge([ 11 | // 12 | ]); 13 | @endphp 14 | 15 | 16 | 17 | 18 | {{ $label ?? $slot }} 19 | 20 | -------------------------------------------------------------------------------- /resources/views/components/button.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | 'color' => 'primary', 5 | 'size' => null, 6 | 'type' => 'button', 7 | 'route' => null, 8 | 'url' => null, 9 | 'href' => null, 10 | 'dismiss' => null, 11 | 'toggle' => null, 12 | 'click' => null, 13 | 'confirm' => false, 14 | ]) 15 | 16 | @php 17 | if ($route) $href = route($route); 18 | else if ($url) $href = url($url); 19 | 20 | $attributes = $attributes->class([ 21 | 'btn btn-' . $color, 22 | 'btn-' . $size => $size, 23 | ])->merge([ 24 | 'type' => !$href ? $type : null, 25 | 'href' => $href, 26 | 'data-bs-dismiss' => $dismiss, 27 | 'data-bs-toggle' => $toggle, 28 | 'wire:click' => $click, 29 | 'onclick' => $confirm ? 'confirm(\'' . __('Are you sure?') . '\') || event.stopImmediatePropagation()' : null, 30 | ]); 31 | @endphp 32 | 33 | <{{ $href ? 'a' : 'button' }} {{ $attributes }}> 34 | 35 | 36 | {{ $label ?? $slot }} 37 | 38 | -------------------------------------------------------------------------------- /resources/views/components/check-label.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | ]) 4 | 5 | @php 6 | $attributes = $attributes->class([ 7 | 'form-check-label', 8 | ])->merge([ 9 | // 10 | ]); 11 | @endphp 12 | 13 | @if($label || !$slot->isEmpty()) 14 | 17 | @endif 18 | -------------------------------------------------------------------------------- /resources/views/components/check.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'checkLabel' => null, 4 | 'help' => null, 5 | 'switch' => false, 6 | 'model' => null, 7 | 'lazy' => false, 8 | ]) 9 | 10 | @php 11 | if ($lazy) $bind = 'lazy'; 12 | else $bind = 'defer'; 13 | 14 | $wireModel = $attributes->whereStartsWith('wire:model')->first(); 15 | $key = $attributes->get('name', $model ?? $wireModel); 16 | $id = $attributes->get('id', $model ?? $wireModel); 17 | $prefix = config('laravel-bootstrap-components.use_with_model_trait') ? 'model.' : null; 18 | 19 | $attributes = $attributes->class([ 20 | 'form-check-input', 21 | 'is-invalid' => $errors->has($key), 22 | ])->merge([ 23 | 'type' => 'checkbox', 24 | 'id' => $id, 25 | 'wire:model.' . $bind => $model ? $prefix . $model : null, 26 | ]); 27 | @endphp 28 | 29 |
30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 | -------------------------------------------------------------------------------- /resources/views/components/close.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'color' => null, 3 | 'dismiss' => null, 4 | ]) 5 | 6 | @php 7 | $attributes = $attributes->class([ 8 | 'btn-close', 9 | 'btn-close-' . $color => $color, 10 | ])->merge([ 11 | 'type' => 'button', 12 | 'data-bs-dismiss' => $dismiss, 13 | ]); 14 | @endphp 15 | 16 | 17 | -------------------------------------------------------------------------------- /resources/views/components/color.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'icon' => null, 4 | 'prepend' => null, 5 | 'append' => null, 6 | 'size' => null, 7 | 'help' => null, 8 | 'model' => null, 9 | 'lazy' => false, 10 | ]) 11 | 12 | @php 13 | if ($lazy) $bind = 'lazy'; 14 | else $bind = 'defer'; 15 | 16 | $wireModel = $attributes->whereStartsWith('wire:model')->first(); 17 | $key = $attributes->get('name', $model ?? $wireModel); 18 | $id = $attributes->get('id', $model ?? $wireModel); 19 | $prefix = config('laravel-bootstrap-components.use_with_model_trait') ? 'model.' : null; 20 | 21 | $attributes = $attributes->class([ 22 | 'form-control form-control-color', 23 | 'form-control-' . $size => $size, 24 | 'rounded-end' => !$append, 25 | 'is-invalid' => $errors->has($key), 26 | ])->merge([ 27 | 'type' => 'color', 28 | 'id' => $id, 29 | 'wire:model.' . $bind => $model ? $prefix . $model : null, 30 | ]); 31 | @endphp 32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 | 46 | 47 |
48 | -------------------------------------------------------------------------------- /resources/views/components/datalist.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'options' => [], 4 | 'icon' => null, 5 | 'prepend' => null, 6 | 'append' => null, 7 | 'size' => null, 8 | 'help' => null, 9 | 'model' => null, 10 | 'debounce' => null, 11 | 'lazy' => false, 12 | ]) 13 | 14 | @php 15 | if ($debounce) $bind = 'debounce.' . (ctype_digit($debounce) ? $debounce : 150) . 'ms'; 16 | else if ($lazy) $bind = 'lazy'; 17 | else $bind = 'defer'; 18 | 19 | $wireModel = $attributes->whereStartsWith('wire:model')->first(); 20 | $key = $attributes->get('name', $model ?? $wireModel); 21 | $id = $attributes->get('id', $model ?? $wireModel); 22 | $prefix = config('laravel-bootstrap-components.use_with_model_trait') ? 'model.' : null; 23 | $list = $attributes->get('list', $key . '_list'); 24 | 25 | $attributes = $attributes->class([ 26 | 'form-control', 27 | 'form-control-' . $size => $size, 28 | 'rounded-end' => !$append, 29 | 'is-invalid' => $errors->has($key), 30 | ])->merge([ 31 | 'list' => $list, 32 | 'id' => $id, 33 | 'wire:model.' . $bind => $model ? $prefix . $model : null, 34 | ]); 35 | @endphp 36 | 37 |
38 | 39 | 40 |
41 | 42 | 43 | 44 | 45 | 46 | @foreach($options as $option) 47 | 50 | 51 | 52 | 53 | 54 |
55 | 56 | 57 |
58 | -------------------------------------------------------------------------------- /resources/views/components/desc.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'term' => null, 3 | 'details' => null, 4 | 'date' => null, 5 | ]) 6 | 7 | @php 8 | $attributes = $attributes->class([ 9 | 'mb-0', 10 | ])->merge([ 11 | // 12 | ]); 13 | @endphp 14 | 15 |
16 |
{{ $term }}
17 | 18 |
19 | @if($details || !$slot->isEmpty()) 20 | {{ $details ?? $slot }} 21 | @elseif($date) 22 | @displayDate($date) 23 | @else 24 | {{ __('N/A') }} 25 | @endif 26 |
27 |
28 | -------------------------------------------------------------------------------- /resources/views/components/dropdown-item.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | 'route' => null, 5 | 'url' => null, 6 | 'href' => null, 7 | 'click' => null, 8 | ]) 9 | 10 | @php 11 | if ($route) $href = route($route); 12 | else if ($url) $href = url($url); 13 | 14 | $attributes = $attributes->class([ 15 | 'dropdown-item', 16 | 'active' => $href == Request::url(), 17 | ])->merge([ 18 | 'type' => !$href ? 'button' : null, 19 | 'href' => $href, 20 | 'wire:click' => $click, 21 | ]); 22 | @endphp 23 | 24 | <{{ $href ? 'a' : 'button' }} {{ $attributes }}> 25 | 26 | 27 | {{ $label ?? $slot }} 28 | 29 | -------------------------------------------------------------------------------- /resources/views/components/dropdown.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | 'items' => null, 5 | 'color' => 'primary', 6 | 'size' => null, 7 | ]) 8 | 9 | @php 10 | $attributes = $attributes->class([ 11 | 'btn btn-' . $color, 12 | 'btn-' . $size => $size, 13 | 'dropdown-toggle', 14 | 'border-0 p-0' => $color == 'link', 15 | ])->merge([ 16 | 'type' => 'button', 17 | 'data-bs-toggle' => 'dropdown', 18 | ]); 19 | @endphp 20 | 21 | 32 | -------------------------------------------------------------------------------- /resources/views/components/error.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'key' => null, 3 | ]) 4 | 5 | @php 6 | $attributes = $attributes->class([ 7 | 'invalid-feedback', 8 | ])->merge([ 9 | // 10 | ]); 11 | @endphp 12 | 13 | @error($key) 14 |
15 | {{ $message }} 16 |
17 | @enderror 18 | -------------------------------------------------------------------------------- /resources/views/components/form.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'submit' => null, 3 | ]) 4 | 5 | @php 6 | $attributes = $attributes->class([ 7 | // 8 | ])->merge([ 9 | 'wire:submit.prevent' => $submit 10 | ]); 11 | @endphp 12 | 13 |
14 | {{ $slot }} 15 |
16 | -------------------------------------------------------------------------------- /resources/views/components/help.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | ]) 4 | 5 | @php 6 | $attributes = $attributes->class([ 7 | 'form-text', 8 | ])->merge([ 9 | // 10 | ]); 11 | @endphp 12 | 13 | @if($label || !$slot->isEmpty()) 14 |
15 | {{ $label ?? $slot }} 16 |
17 | @endif 18 | -------------------------------------------------------------------------------- /resources/views/components/icon.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'name' => null, 3 | 'style' => config('laravel-bootstrap-components.font_awesome_style'), 4 | 'size' => null, 5 | 'color' => null, 6 | 'spin' => false, 7 | 'pulse' => false, 8 | ]) 9 | 10 | @php 11 | $attributes = $attributes->class([ 12 | 'fa' . Str::limit($style, 1, null) . ' fa-fw fa-' . $name, 13 | 'fa-' . $size => $size, 14 | 'text-' . $color => $color, 15 | 'fa-spin' => $spin, 16 | 'fa-pulse' => $pulse, 17 | ])->merge([ 18 | // 19 | ]); 20 | @endphp 21 | 22 | @if($name) 23 | 24 | @endif 25 | -------------------------------------------------------------------------------- /resources/views/components/image.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'asset' => null, 3 | 'mix' => null, 4 | 'src' => null, 5 | 'fluid' => false, 6 | 'thumbnail' => false, 7 | 'rounded' => false, 8 | ]) 9 | 10 | @php 11 | if ($asset) $src = asset($asset); 12 | else if ($mix) $src = mix($mix); 13 | 14 | $attributes = $attributes->class([ 15 | 'img-fluid' => $fluid, 16 | 'img-thumbnail' => $thumbnail, 17 | 'rounded' => $rounded, 18 | ])->merge([ 19 | 'src' => $src, 20 | ]); 21 | @endphp 22 | 23 | 24 | -------------------------------------------------------------------------------- /resources/views/components/input-addon.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | ]) 5 | 6 | @php 7 | $attributes = $attributes->class([ 8 | 'input-group-text', 9 | ])->merge([ 10 | // 11 | ]); 12 | @endphp 13 | 14 | @if($icon || $label || !$slot->isEmpty()) 15 | 16 | 17 | 18 | {{ $label ?? $slot }} 19 | 20 | @endif 21 | -------------------------------------------------------------------------------- /resources/views/components/input.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'type' => 'text', 4 | 'icon' => null, 5 | 'prepend' => null, 6 | 'append' => null, 7 | 'size' => null, 8 | 'help' => null, 9 | 'model' => null, 10 | 'debounce' => false, 11 | 'lazy' => false, 12 | ]) 13 | 14 | @php 15 | if ($type == 'number') $inputmode = 'decimal'; 16 | else if (in_array($type, ['tel', 'search', 'email', 'url'])) $inputmode = $type; 17 | else $inputmode = 'text'; 18 | 19 | if ($debounce) $bind = 'debounce.' . (ctype_digit($debounce) ? $debounce : 150) . 'ms'; 20 | else if ($lazy) $bind = 'lazy'; 21 | else $bind = 'defer'; 22 | 23 | $wireModel = $attributes->whereStartsWith('wire:model')->first(); 24 | $key = $attributes->get('name', $model ?? $wireModel); 25 | $id = $attributes->get('id', $model ?? $wireModel); 26 | $prefix = config('laravel-bootstrap-components.use_with_model_trait') ? 'model.' : null; 27 | 28 | $attributes = $attributes->class([ 29 | 'form-control', 30 | 'form-control-' . $size => $size, 31 | 'rounded-end' => !$append, 32 | 'is-invalid' => $errors->has($key), 33 | ])->merge([ 34 | 'type' => $type, 35 | 'inputmode' => $inputmode, 36 | 'id' => $id, 37 | 'wire:model.' . $bind => $model ? $prefix . $model : null, 38 | ]); 39 | @endphp 40 | 41 |
42 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 |
56 | -------------------------------------------------------------------------------- /resources/views/components/label.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | ]) 4 | 5 | @php 6 | $attributes = $attributes->class([ 7 | 'form-label', 8 | ])->merge([ 9 | // 10 | ]); 11 | @endphp 12 | 13 | @if($label || !$slot->isEmpty()) 14 | 17 | @endif 18 | -------------------------------------------------------------------------------- /resources/views/components/link.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | 'color' => null, 5 | 'route' => null, 6 | 'url' => null, 7 | 'href' => '#', 8 | 'click' => null, 9 | ]) 10 | 11 | @php 12 | if ($route) $href = route($route); 13 | else if ($url) $href = url($url); 14 | 15 | $attributes = $attributes->class([ 16 | 'text-' . $color => $color, 17 | ])->merge([ 18 | 'href' => $href, 19 | 'wire:click.prevent' => $click, 20 | ]); 21 | @endphp 22 | 23 | 24 | 25 | 26 | {{ $label ?? $slot }} 27 | 28 | -------------------------------------------------------------------------------- /resources/views/components/nav-dropdown.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | 'items' => null, 5 | ]) 6 | 7 | @php 8 | $attributes = $attributes->class([ 9 | 'nav-link', 10 | 'dropdown-toggle', 11 | ])->merge([ 12 | 'href' => '#', 13 | 'data-bs-toggle' => 'dropdown', 14 | ]); 15 | @endphp 16 | 17 | 28 | -------------------------------------------------------------------------------- /resources/views/components/nav-link.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'icon' => null, 3 | 'label' => null, 4 | 'route' => null, 5 | 'url' => null, 6 | 'href' => null, 7 | 'click' => null, 8 | ]) 9 | 10 | @php 11 | if ($route) $href = route($route); 12 | else if ($url) $href = url($url); 13 | 14 | $attributes = $attributes->class([ 15 | 'nav-link', 16 | 'active' => $href == Request::url(), 17 | ])->merge([ 18 | 'href' => $href, 19 | 'wire:click.prevent' => $click, 20 | ]); 21 | @endphp 22 | 23 | 24 | 25 | 26 | {{ $label ?? $slot }} 27 | 28 | -------------------------------------------------------------------------------- /resources/views/components/pagination.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'links' => null, 3 | 'justify' => 'center', 4 | ]) 5 | 6 | @php 7 | $attributes = $attributes->class([ 8 | 'd-flex', 9 | 'justify-content-' . $justify => $justify, 10 | ])->merge([ 11 | // 12 | ]); 13 | @endphp 14 | 15 | @if($links->hasPages()) 16 |
17 | @if(isset($this) && method_exists($this, 'initializeWithPagination')) 18 |
19 | {{ $links->links('livewire::simple-bootstrap') }} 20 |
21 | 22 |
23 | {{ $links->links('livewire::bootstrap') }} 24 |
25 | @else 26 |
27 | {{ $links->links('pagination::simple-bootstrap-4') }} 28 |
29 | 30 |
31 | {{ $links->links('pagination::bootstrap-4') }} 32 |
33 | @endif 34 |
35 | @endif 36 | -------------------------------------------------------------------------------- /resources/views/components/progress.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'percent' => 0, 4 | 'color' => 'primary', 5 | 'height' => null, 6 | 'animated' => false, 7 | 'striped' => false, 8 | ]) 9 | 10 | @php 11 | $attributes = $attributes->class([ 12 | 'progress-bar', 13 | 'progress-bar-animated' => $animated, 14 | 'progress-bar-striped' => $striped, 15 | 'bg-' . $color => $color, 16 | ])->merge([ 17 | 'style' => 'width: ' . $percent . '%', 18 | ]); 19 | @endphp 20 | 21 |
22 |
23 | {{ $label ?? $slot }} 24 |
25 |
26 | -------------------------------------------------------------------------------- /resources/views/components/radio.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'options' => [], 4 | 'help' => null, 5 | 'switch' => false, 6 | 'model' => null, 7 | 'lazy' => false, 8 | ]) 9 | 10 | @php 11 | if ($lazy) $bind = 'lazy'; 12 | else $bind = 'defer'; 13 | 14 | $wireModel = $attributes->whereStartsWith('wire:model')->first(); 15 | $key = $attributes->get('name', $model ?? $wireModel); 16 | $id = $attributes->get('id', $model ?? $wireModel); 17 | $prefix = config('laravel-bootstrap-components.use_with_model_trait') ? 'model.' : null; 18 | $options = Arr::isAssoc($options) ? $options : array_combine($options, $options); 19 | 20 | $attributes = $attributes->class([ 21 | 'form-check-input', 22 | 'is-invalid' => $errors->has($key), 23 | ])->merge([ 24 | 'type' => 'radio', 25 | 'name' => $key, 26 | 'wire:model.' . $bind => $model ? $prefix . $model : null, 27 | ]); 28 | @endphp 29 | 30 |
31 | 32 | 33 | @foreach($options as $optionValue => $optionLabel) 34 |
35 | @php($optionId = $id . '_' . $loop->index) 36 | 37 | merge(['id' => $optionId, 'value' => $optionValue]) }}> 38 | 39 | 40 | 41 | @if($loop->last) 42 | 43 | 44 | 45 | @endif 46 |
47 | @endforeach 48 |
49 | -------------------------------------------------------------------------------- /resources/views/components/select.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'placeholder' => null, 4 | 'options' => [], 5 | 'icon' => null, 6 | 'prepend' => null, 7 | 'append' => null, 8 | 'size' => null, 9 | 'help' => null, 10 | 'model' => null, 11 | 'lazy' => false, 12 | ]) 13 | 14 | @php 15 | if ($lazy) $bind = 'lazy'; 16 | else $bind = 'defer'; 17 | 18 | $wireModel = $attributes->whereStartsWith('wire:model')->first(); 19 | $key = $attributes->get('name', $model ?? $wireModel); 20 | $id = $attributes->get('id', $model ?? $wireModel); 21 | $prefix = config('laravel-bootstrap-components.use_with_model_trait') ? 'model.' : null; 22 | $options = Arr::isAssoc($options) ? $options : array_combine($options, $options); 23 | 24 | $attributes = $attributes->class([ 25 | 'form-select', 26 | 'form-select-' . $size => $size, 27 | 'rounded-end' => !$append, 28 | 'is-invalid' => $errors->has($key), 29 | ])->merge([ 30 | 'id' => $id, 31 | 'wire:model.' . $bind => $model ? $prefix . $model : null, 32 | ]); 33 | @endphp 34 | 35 |
36 | 37 | 38 |
39 | 40 | 41 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 |
56 | -------------------------------------------------------------------------------- /resources/views/components/textarea.blade.php: -------------------------------------------------------------------------------- 1 | @props([ 2 | 'label' => null, 3 | 'icon' => null, 4 | 'prepend' => null, 5 | 'append' => null, 6 | 'rows' => 3, 7 | 'size' => null, 8 | 'help' => null, 9 | 'model' => null, 10 | 'debounce' => false, 11 | 'lazy' => false, 12 | ]) 13 | 14 | @php 15 | if ($debounce) $bind = 'debounce.' . (ctype_digit($debounce) ? $debounce : 150) . 'ms'; 16 | else if ($lazy) $bind = 'lazy'; 17 | else $bind = 'defer'; 18 | 19 | $wireModel = $attributes->whereStartsWith('wire:model')->first(); 20 | $key = $attributes->get('name', $model ?? $wireModel); 21 | $id = $attributes->get('id', $model ?? $wireModel); 22 | $prefix = config('laravel-bootstrap-components.use_with_model_trait') ? 'model.' : null; 23 | 24 | $attributes = $attributes->class([ 25 | 'form-control', 26 | 'form-control-' . $size => $size, 27 | 'rounded-end' => !$append, 28 | 'is-invalid' => $errors->has($key), 29 | ])->merge([ 30 | 'id' => $id, 31 | 'rows' => $rows, 32 | 'wire:model.' . $bind => $model ? $prefix . $model : null, 33 | ]); 34 | @endphp 35 | 36 |
37 | 38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
48 | 49 | 50 |
51 | -------------------------------------------------------------------------------- /src/Providers/LaravelBootstrapComponentsProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__ . '/../../resources/views', 'bs'); 12 | 13 | $this->publishes( 14 | [__DIR__ . '/../../config/laravel-bootstrap-components.php' => config_path('laravel-bootstrap-components.php')], 15 | ['laravel-bootstrap-components', 'laravel-bootstrap-components:config'] 16 | ); 17 | 18 | $this->publishes( 19 | [__DIR__ . '/../../resources/views' => resource_path('views/vendor/bs')], 20 | ['laravel-bootstrap-components', 'laravel-bootstrap-components:views'] 21 | ); 22 | } 23 | 24 | public function register() 25 | { 26 | $this->mergeConfigFrom(__DIR__ . '/../../config/laravel-bootstrap-components.php', 'laravel-bootstrap-components'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Traits/WithModel.php: -------------------------------------------------------------------------------- 1 | modelCollection) { 17 | $this->modelCollection = collect($this->model); 18 | } 19 | 20 | return $this->modelCollection; 21 | } 22 | 23 | public function setModel($key, $value = null) 24 | { 25 | if ($key instanceof Model) { 26 | $key = $key->toArray(); 27 | } 28 | 29 | if (is_array($key)) { 30 | foreach ($key as $arrayKey => $arrayValue) { 31 | Arr::set($this->model, $arrayKey, $arrayValue); 32 | } 33 | } else { 34 | Arr::set($this->model, $key, $value); 35 | } 36 | } 37 | 38 | public function addModelItem($key) 39 | { 40 | $array = $this->getModel($key); 41 | $arrayKey = $array ? max(array_keys($array)) + 1 : 0; 42 | 43 | Arr::set($this->model, $key . '.' . $arrayKey, null); 44 | 45 | $this->rekeyModelItems($key); 46 | } 47 | 48 | public function removeModelItem($key, $arrayKey) 49 | { 50 | Arr::forget($this->model, $key . '.' . $arrayKey); 51 | 52 | $this->rekeyModelItems($key); 53 | } 54 | 55 | public function rekeyModelItems($key) 56 | { 57 | $this->setModel($key, array_values($this->getModel($key))); 58 | } 59 | 60 | public function orderModelItem($key, $arrayKey, $direction) 61 | { 62 | $arrayValue = $this->getModel($key . '.' . $arrayKey); 63 | $swapKey = strtolower($direction) == 'up' ? $arrayKey - 1 : $arrayKey + 1; 64 | 65 | if ($swapValue = $this->getModel($key . '.' . $swapKey)) { 66 | $this->setModel($key . '.' . $arrayKey, $swapValue); 67 | $this->setModel($key . '.' . $swapKey, $arrayValue); 68 | } 69 | } 70 | 71 | public function validateModel($rules = null) 72 | { 73 | $validator = Validator::make($this->model, $rules ?? $this->getRules()); 74 | $validatedModel = $validator->validate(); 75 | 76 | $this->resetErrorBag(); 77 | 78 | return $validatedModel; 79 | } 80 | 81 | public function updatingModelSearch() 82 | { 83 | if (method_exists($this, 'resetPage')) { 84 | $this->resetPage(); 85 | } 86 | } 87 | } 88 | --------------------------------------------------------------------------------