├── resources ├── views │ ├── fields │ │ ├── range.blade.php │ │ ├── textarea.blade.php │ │ ├── label.blade.php │ │ ├── radio.blade.php │ │ ├── simplemde.blade.php │ │ ├── input.blade.php │ │ ├── code.blade.php │ │ ├── group.blade.php │ │ ├── quill.blade.php │ │ ├── password.blade.php │ │ ├── radiobutton.blade.php │ │ ├── switch.blade.php │ │ ├── select.blade.php │ │ ├── datetime.blade.php │ │ ├── checkbox.blade.php │ │ ├── numberRange.blade.php │ │ ├── relation.blade.php │ │ ├── dataRange.blade.php │ │ ├── matrix.blade.php │ │ └── map.blade.php │ ├── partials │ │ ├── fields │ │ │ ├── hidden.blade.php │ │ │ ├── clear.blade.php │ │ │ └── matrixRow.blade.php │ │ ├── layouts │ │ │ ├── dt.blade.php │ │ │ ├── td.blade.php │ │ │ ├── selectedTd.blade.php │ │ │ ├── filter.blade.php │ │ │ └── th.blade.php │ │ ├── notification-wrap.blade.php │ │ ├── state.blade.php │ │ ├── update-assets.blade.php │ │ ├── profile.blade.php │ │ ├── search.blade.php │ │ ├── alert.blade.php │ │ ├── notification.blade.php │ │ ├── confirm.blade.php │ │ └── search-result.blade.php │ ├── layouts │ │ ├── browsing.blade.php │ │ ├── blank.blade.php │ │ ├── columns.blade.php │ │ ├── tabMenu.blade.php │ │ ├── row.blade.php │ │ ├── persona.blade.php │ │ ├── split.blade.php │ │ ├── facepile.blade.php │ │ ├── listener.blade.php │ │ ├── legend.blade.php │ │ ├── filter.blade.php │ │ ├── metric.blade.php │ │ ├── accordion.blade.php │ │ └── block.blade.php │ ├── actions │ │ ├── link.blade.php │ │ ├── button.blade.php │ │ ├── dropdown.blade.php │ │ ├── modal.blade.php │ │ ├── toggle.blade.php │ │ └── menu.blade.php │ ├── dummy │ │ └── block.blade.php │ ├── workspace │ │ ├── full.blade.php │ │ └── compact.blade.php │ ├── components │ │ ├── popover.blade.php │ │ ├── stream.blade.php │ │ └── notification.blade.php │ ├── auth │ │ ├── login.blade.php │ │ ├── impersonation.blade.php │ │ └── signin.blade.php │ ├── header.blade.php │ ├── auth.blade.php │ └── errors │ │ └── 404.blade.php ├── sass │ ├── plugins │ │ ├── tom-select.scss │ │ ├── accordion.scss │ │ └── load-opacity.scss │ └── app.scss └── js │ ├── controllers │ ├── toggle_controller.js │ ├── menu_controller.js │ ├── tooltip_controller.js │ ├── checkbox_controller.js │ ├── popover_controller.js │ ├── reload_controller.js │ ├── radiobutton_controller.js │ ├── code_controller.js │ ├── viewport-entrance-toggle_controller.js │ ├── browsing_controller.js │ ├── button_controller.js │ ├── password_controller.js │ ├── pull-to-refresh_controller.js │ ├── input_controller.js │ ├── confirm_controller.js │ ├── toast_controller.js │ └── search_controller.js │ ├── orchid.js │ └── app.js ├── src ├── Screen │ ├── Concerns │ │ ├── ComplexFieldConcern.php │ │ ├── Makeable.php │ │ └── Multipliable.php │ ├── Contracts │ │ ├── Actionable.php │ │ ├── Groupable.php │ │ ├── Personable.php │ │ ├── Cardable.php │ │ ├── Fieldable.php │ │ └── Searchable.php │ ├── Fields │ │ ├── ViewField.php │ │ ├── Label.php │ │ ├── Map.php │ │ ├── NumberRange.php │ │ └── Range.php │ ├── Layouts │ │ ├── Facepile.php │ │ ├── Persona.php │ │ ├── Columns.php │ │ ├── Blank.php │ │ ├── View.php │ │ ├── Tabs.php │ │ ├── Content.php │ │ ├── TabMenu.php │ │ ├── Wrapper.php │ │ ├── Metric.php │ │ ├── Card.php │ │ ├── Component.php │ │ ├── Rows.php │ │ └── Selection.php │ ├── Commander.php │ ├── Exceptions │ │ └── FieldRequiredAttributeException.php │ ├── Components │ │ ├── Cells │ │ │ ├── DateTime.php │ │ │ ├── Time.php │ │ │ ├── Number.php │ │ │ ├── Percentage.php │ │ │ ├── Boolean.php │ │ │ ├── DateTimeSplit.php │ │ │ ├── Currency.php │ │ │ └── Text.php │ │ └── Popover.php │ ├── Sight.php │ ├── AsMultiSource.php │ ├── Actions │ │ ├── DropDown.php │ │ └── Toggle.php │ ├── AsSource.php │ └── CanSee.php ├── Support │ ├── Attributes │ │ └── FlushOctaneState.php │ ├── BootstrapIconsPath.php │ ├── Testing │ │ ├── ScreenTesting.php │ │ └── MakesHttpRequestsWrapper.php │ ├── Names.php │ ├── Formats.php │ ├── Facades │ │ ├── Alert.php │ │ └── Dashboard.php │ ├── Assert.php │ └── Locale.php ├── Access │ ├── UserSwitch.php │ ├── UserInterface.php │ └── RoleInterface.php ├── Platform │ ├── Events │ │ ├── InstallEvent.php │ │ ├── ReplicateFileEvent.php │ │ ├── UploadedFileEvent.php │ │ ├── UploadFileEvent.php │ │ ├── RemoveRoleEvent.php │ │ └── AddRoleEvent.php │ ├── Components │ │ ├── Stream.php │ │ └── Notification.php │ ├── Http │ │ ├── Controllers │ │ │ ├── SearchController.php │ │ │ ├── IndexController.php │ │ │ ├── SortableController.php │ │ │ └── Controller.php │ │ ├── Middleware │ │ │ └── BladeIcons.php │ │ ├── Requests │ │ │ └── RelationRequest.php │ │ └── Layouts │ │ │ └── NotificationTable.php │ ├── Commands │ │ ├── GeneratorCommand.php │ │ ├── PublishCommand.php │ │ ├── RowsCommand.php │ │ ├── ChartCommand.php │ │ ├── ScreenCommand.php │ │ ├── TableCommand.php │ │ ├── FilterCommand.php │ │ ├── TabMenuCommand.php │ │ ├── ListenerCommand.php │ │ ├── PresenterCommand.php │ │ └── SelectionCommand.php │ ├── Configuration │ │ ├── ManagesPackage.php │ │ └── ManagesModelOptions.php │ ├── Models │ │ └── Role.php │ ├── Concerns │ │ └── Sortable.php │ └── ItemPermission.php ├── Filters │ ├── Types │ │ ├── Where.php │ │ ├── WhereDate.php │ │ ├── WhereBetween.php │ │ ├── Ilike.php │ │ ├── WhereIn.php │ │ ├── WhereMaxMin.php │ │ ├── WhereDateStartEnd.php │ │ └── Like.php │ └── BaseHttpEloquentFilter.php └── Attachment │ ├── Models │ └── Attachmentable.php │ ├── Attachable.php │ └── Contracts │ └── Engine.php ├── stubs ├── presenter.stub ├── selection.stub ├── app │ └── Orchid │ │ ├── Layouts │ │ ├── User │ │ │ ├── UserFiltersLayout.php │ │ │ ├── UserRoleLayout.php │ │ │ ├── UserEditLayout.php │ │ │ ├── UserPasswordLayout.php │ │ │ └── ProfilePasswordLayout.php │ │ ├── Examples │ │ │ ├── ChartPieExample.php │ │ │ ├── ChartPercentageExample.php │ │ │ ├── ChartBarExample.php │ │ │ ├── ExampleElements.php │ │ │ ├── TabMenuExample.php │ │ │ └── ChartLineExample.php │ │ └── Role │ │ │ ├── RoleEditLayout.php │ │ │ └── RoleListLayout.php │ │ └── Screens │ │ └── PlatformScreen.php ├── chart.stub ├── tabMenu.stub ├── rows.stub ├── table.stub ├── field.blade.stub ├── field.stub ├── listener.stub ├── screen.stub └── filters.stub ├── .babelrc ├── database ├── seeders │ ├── RolesTableSeeder.php │ ├── UsersTableSeeder.php │ └── OrchidDatabaseSeeder.php ├── migrations │ ├── 2015_04_12_000000_create_orchid_users_table.php │ ├── 2015_10_19_214424_create_orchid_roles_table.php │ ├── 2017_09_17_125801_create_notifications_table.php │ └── 2015_10_19_214425_create_orchid_role_users_table.php └── factories │ └── AttachmentFactory.php ├── public ├── mix-manifest.json ├── manifest.json └── favicon.svg ├── .eslintrc.json ├── routes └── auth.php ├── LICENSE ├── package.json └── psalm.xml /resources/views/fields/range.blade.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/views/fields/textarea.blade.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/views/partials/fields/hidden.blade.php: -------------------------------------------------------------------------------- 1 |
2 | {!! $slot !!} 3 |
-------------------------------------------------------------------------------- /resources/views/partials/layouts/dt.blade.php: -------------------------------------------------------------------------------- 1 | {{$title}} 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/views/partials/notification-wrap.blade.php: -------------------------------------------------------------------------------- 1 |
2 | {!! $table !!} 3 |
4 | -------------------------------------------------------------------------------- /resources/views/fields/label.blade.php: -------------------------------------------------------------------------------- 1 | @if(strlen($value) > 0) 2 |

3 | {{ $value }} 4 |

5 | @endif 6 | -------------------------------------------------------------------------------- /resources/sass/plugins/tom-select.scss: -------------------------------------------------------------------------------- 1 | .ts-control { 2 | box-shadow: none !important; 3 | } 4 | 5 | .ts-control > input { 6 | min-width: auto; 7 | } 8 | -------------------------------------------------------------------------------- /resources/views/partials/state.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/views/layouts/browsing.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /resources/views/fields/radio.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | -------------------------------------------------------------------------------- /resources/views/layouts/blank.blade.php: -------------------------------------------------------------------------------- 1 | @foreach($manyForms as $key => $column) 2 | @foreach(\Illuminate\Support\Arr::wrap($column) as $item) 3 | {!! $item ?? '' !!} 4 | @endforeach 5 | @endforeach 6 | -------------------------------------------------------------------------------- /src/Screen/Concerns/ComplexFieldConcern.php: -------------------------------------------------------------------------------- 1 | 5 | @isset($icon) 6 | 7 | @endisset 8 | 9 | {{ $name ?? '' }} 10 | 11 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@babel/plugin-proposal-class-properties", 4 | "@babel/plugin-transform-block-scoping" 5 | ], 6 | "presets": [ 7 | [ 8 | "@babel/preset-env", 9 | { 10 | "modules": false 11 | } 12 | ] 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /resources/views/partials/fields/clear.blade.php: -------------------------------------------------------------------------------- 1 |
2 | {!! $slot !!} 3 | 4 | @if($field->has('help')) 5 | 6 | {!! $field->get('help') !!} 7 | 8 | @endif 9 |
10 | -------------------------------------------------------------------------------- /resources/js/controllers/toggle_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | 3 | export default class extends ApplicationController { 4 | static targets = ["button"] 5 | 6 | toggle() { 7 | this.buttonTarget.click() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /resources/views/layouts/columns.blade.php: -------------------------------------------------------------------------------- 1 |
2 | @foreach($manyForms as $key => $column) 3 |
4 | @foreach($column as $item) 5 | {!! $item ?? '' !!} 6 | @endforeach 7 |
8 | @endforeach 9 |
10 | -------------------------------------------------------------------------------- /src/Screen/Contracts/Actionable.php: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Access/UserSwitch.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Dummy {{ Str::random(8) }}

4 |
5 | 6 | -------------------------------------------------------------------------------- /resources/js/controllers/menu_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | 3 | export default class extends ApplicationController { 4 | 5 | /** 6 | * 7 | */ 8 | toggle(event) { 9 | document.body.classList.toggle('menu-open'); 10 | event.preventDefault(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /resources/views/layouts/tabMenu.blade.php: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /stubs/selection.stub: -------------------------------------------------------------------------------- 1 | name($name); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Platform/Events/InstallEvent.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | @empty(!$datalist) 8 | 9 | @foreach($datalist as $item) 10 | 13 | @endempty 14 | -------------------------------------------------------------------------------- /resources/js/controllers/tooltip_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | import {Tooltip} from 'bootstrap'; 3 | 4 | export default class extends ApplicationController { 5 | 6 | /** 7 | * 8 | */ 9 | connect() { 10 | this.tooltip = new Tooltip(this.element, { 11 | boundary: 'window' 12 | }) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /resources/views/fields/code.blade.php: -------------------------------------------------------------------------------- 1 |
7 |
8 | 9 |
10 | -------------------------------------------------------------------------------- /resources/views/workspace/full.blade.php: -------------------------------------------------------------------------------- 1 | @extends('platform::app') 2 | 3 | @section('body') 4 | 5 |
6 |
7 | @yield('workspace') 8 | 9 | @includeFirst([config('platform.template.footer'), 'platform::footer']) 10 |
11 |
12 | 13 | @endsection 14 | -------------------------------------------------------------------------------- /src/Screen/Contracts/Personable.php: -------------------------------------------------------------------------------- 1 | where($this->column, $this->getHttpValue()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /database/seeders/RolesTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/js/orchid.js": "/js/orchid.js?id=b138a2039a1af3043203796830122ef2", 3 | "/js/manifest.js": "/js/manifest.js?id=a0cf0beb2ef26ed536c04092e6558f2a", 4 | "/css/orchid.rtl.css": "/css/orchid.rtl.css?id=42984b47f51b99b13764f6738c2f9450", 5 | "/css/orchid.css": "/css/orchid.css?id=47f20d5197224b071b164da38b675a4e", 6 | "/js/vendor.js": "/js/vendor.js?id=ebad221ec97b49e74a1477c98c2b0551" 7 | } 8 | -------------------------------------------------------------------------------- /resources/views/layouts/row.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | @empty(!$title) 4 |
5 | 6 | {{ $title }} 7 | 8 |
9 | @endempty 10 | 11 |
12 | {!! $form ?? '' !!} 13 |
14 |
15 | -------------------------------------------------------------------------------- /database/seeders/UsersTableSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/views/workspace/compact.blade.php: -------------------------------------------------------------------------------- 1 | @extends('platform::app') 2 | 3 | @section('body') 4 | 5 |
6 |
7 | @yield('workspace') 8 | 9 | @includeFirst([config('platform.template.footer'), 'platform::footer']) 10 |
11 |
12 | 13 | @endsection 14 | -------------------------------------------------------------------------------- /src/Access/UserInterface.php: -------------------------------------------------------------------------------- 1 | whereDate($this->column, $this->getHttpValue()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /resources/js/controllers/checkbox_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | 3 | export default class extends ApplicationController { 4 | /** 5 | * 6 | */ 7 | connect() { 8 | const checkbox = this.element.querySelector('input:not([hidden])'); 9 | 10 | if (checkbox) { 11 | checkbox.indeterminate = this.data.get('indeterminate') 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /resources/views/layouts/persona.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @empty(!$image) 3 | 4 | 5 | 6 | @endempty 7 |
8 |

{{ $title }}

9 | {{ $subTitle }} 10 |
11 |
12 | -------------------------------------------------------------------------------- /src/Filters/Types/WhereBetween.php: -------------------------------------------------------------------------------- 1 | whereBetween($this->column, $this->getHttpValue()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Support/BootstrapIconsPath.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | @isset($icon) 11 | 12 | @endisset 13 | 14 | {{ $name ?? '' }} 15 | 16 | -------------------------------------------------------------------------------- /resources/views/partials/layouts/td.blade.php: -------------------------------------------------------------------------------- 1 | $width, 5 | "$style" => $style, 6 | ]) 7 | > 8 |
9 | @isset($render) 10 | {!! $value !!} 11 | @else 12 | {{ $value }} 13 | @endisset 14 |
15 | 16 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/User/UserFiltersLayout.php: -------------------------------------------------------------------------------- 1 | view = $view; 20 | 21 | return $this; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Screen/Contracts/Cardable.php: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Filters/Types/Ilike.php: -------------------------------------------------------------------------------- 1 | where( 15 | $this->column, 16 | 'ILIKE', 17 | '%'.$this->getHttpValue().'%' 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Platform/Components/Stream.php: -------------------------------------------------------------------------------- 1 | $widthColumns !== null, 5 | ])> 6 | @foreach($group as $field) 7 |
10 | {!! $field !!} 11 |
12 | @endforeach 13 | 14 | -------------------------------------------------------------------------------- /stubs/tabMenu.stub: -------------------------------------------------------------------------------- 1 | route(config('platform.index')), 20 | ]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources/js/app.js": { 3 | "file": "assets/app.js?v=6d507ed2", 4 | "isEntry": true, 5 | "src": "resources/js/app.js", 6 | "integrity": "sha384-r0qKRGCKpByrh/uftoOOc4So8tVNZJezahxoDhUFcvUVetOvuEhOqzewSUzQ2XTN" 7 | }, 8 | "resources/sass/app.scss": { 9 | "file": "assets/app.css?v=af1ca96b", 10 | "isEntry": true, 11 | "src": "resources/sass/app.scss", 12 | "integrity": "sha384-+JqLG6zZecAiFDFxLSiTiLmEPwXoZLx0u5yQwWjQhrhcIOPgk2+hLAGeY+ZN6OGL" 13 | } 14 | } -------------------------------------------------------------------------------- /src/Platform/Events/ReplicateFileEvent.php: -------------------------------------------------------------------------------- 1 | 7 | @isset($icon) 8 | 9 | @endisset 10 | 11 | {{ $name ?? '' }} 12 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /src/Platform/Http/Controllers/SearchController.php: -------------------------------------------------------------------------------- 1 | Dashboard::search($query), 17 | 'query' => $query, 18 | ]); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/views/layouts/split.blade.php: -------------------------------------------------------------------------------- 1 |
2 | @foreach($manyForms as $key => $column) 3 |
$loop->index % 2 == 0, 6 | $columnClass[1] . ' order-md-last' => $loop->index % 2 != 0, 7 | 'order-first' => $reverseOnPhone && $loop->index % 2 != 0 8 | ])> 9 | @foreach($column as $item) 10 | {!! $item ?? '' !!} 11 | @endforeach 12 |
13 | @endforeach 14 |
15 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/Examples/ChartBarExample.php: -------------------------------------------------------------------------------- 1 | 8 |
9 |
11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Platform/Http/Middleware/BladeIcons.php: -------------------------------------------------------------------------------- 1 | iconFinder->setSize('1.25em', '1.25em'); 20 | 21 | return $next($request); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Filters/Types/WhereIn.php: -------------------------------------------------------------------------------- 1 | getHttpValue(); 16 | 17 | $value = is_array($query) ? $query : Str::of($query)->explode(','); 18 | 19 | return $builder->whereIn($this->column, $value); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /resources/views/fields/password.blade.php: -------------------------------------------------------------------------------- 1 |
4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | -------------------------------------------------------------------------------- /resources/views/components/stream.blade.php: -------------------------------------------------------------------------------- 1 | @props(['target', 'action', 'push', 'rule' => \Orchid\Support\Facades\Dashboard::isPartialRequest()]) 2 | 3 | 4 | @if(filter_var($rule, FILTER_VALIDATE_BOOLEAN)) 5 | @fragment($target) 6 | 7 | 10 | 11 | @endfragment 12 | @elseif(!empty($push)) 13 | @push($push) 14 | {!! $slot !!} 15 | @endpush 16 | @else 17 | {!! $slot !!} 18 | @endif 19 | -------------------------------------------------------------------------------- /src/Support/Testing/ScreenTesting.php: -------------------------------------------------------------------------------- 1 | parameters($parameters); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/views/layouts/facepile.blade.php: -------------------------------------------------------------------------------- 1 |
2 | @foreach($users as $user) 3 | 9 | {{ $user->title() }} 12 | 13 | @endforeach 14 |
15 | 16 | -------------------------------------------------------------------------------- /resources/views/layouts/listener.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
8 | @foreach($manyForms as $layouts) 9 | @foreach($layouts as $layout) 10 | {!! $layout ?? '' !!} 11 | @endforeach 12 | @endforeach 13 |
14 |
15 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Facepile.php: -------------------------------------------------------------------------------- 1 | template, [ 24 | 'users' => $users, 25 | ]); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Screen/Commander.php: -------------------------------------------------------------------------------- 1 | commandBar()) 22 | ->map(static fn (Actionable $command) => $command->build($repository)) 23 | ->filter() 24 | ->all(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /stubs/table.stub: -------------------------------------------------------------------------------- 1 | { 16 | axios({ method, url }).then((response) => { 17 | this.element.innerHTML = response.data; 18 | }); 19 | }, interval); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Attachment/Models/Attachmentable.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | @foreach($options as $key => $option) 5 | 12 | @endforeach 13 |
14 | 15 | -------------------------------------------------------------------------------- /resources/views/partials/update-assets.blade.php: -------------------------------------------------------------------------------- 1 | @if(!Dashboard::assetsAreCurrent()) 2 |
3 |
4 | 5 |

{{ __("Complete the update.") }}

6 |
7 | 8 |

{{ __("The published Orchid assets are not up-to-date with the installed version. To update, run:") }}

9 | php artisan orchid:publish 10 |
11 | @endif 12 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true, 6 | "jquery": true 7 | }, 8 | "rules": { 9 | "indent": [ 10 | "error", 11 | 4 12 | ], 13 | "linebreak-style": [ 14 | "error", 15 | "unix" 16 | ], 17 | "quotes": [ 18 | "error", 19 | "single" 20 | ], 21 | "class-methods-use-this": 0, 22 | "radix": ["error", "as-needed"] 23 | }, 24 | "extends": "airbnb-base", 25 | "globals": { 26 | "axios": true, 27 | "Turbolinks": true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Persona.php: -------------------------------------------------------------------------------- 1 | template, [ 20 | 'title' => $user->title(), 21 | 'subTitle' => $user->subTitle(), 22 | 'image' => $user->image(), 23 | 'url' => $user->url(), 24 | ]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Screen/Exceptions/FieldRequiredAttributeException.php: -------------------------------------------------------------------------------- 1 | message = 'Field must have the following attribute: '.$attribute; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Platform/Commands/GeneratorCommand.php: -------------------------------------------------------------------------------- 1 | laravel->basePath('stubs/orchid/platform/'.trim($stub, '/')); 19 | 20 | return file_exists($path) 21 | ? $path 22 | : Dashboard::path('stubs/'.$stub); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Filters/Types/WhereMaxMin.php: -------------------------------------------------------------------------------- 1 | getHttpValue(); 15 | 16 | $builder->when($value['min'] ?? null, fn (Builder $query) => $query->where($this->column, '>=', $value['min'])); 17 | $builder->when($value['max'] ?? null, fn (Builder $query) => $query->where($this->column, '<=', $value['max'])); 18 | 19 | return $builder; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /resources/views/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | @extends('platform::auth') 2 | @section('title',__('Sign in to your account')) 3 | 4 | @section('content') 5 |

{{__('Sign in to your account')}}

6 | 7 |
14 | @csrf 15 | 16 | @includeWhen($isLockUser,'platform::auth.lockme') 17 | @includeWhen(!$isLockUser,'platform::auth.signin') 18 |
19 | @endsection 20 | -------------------------------------------------------------------------------- /resources/views/partials/layouts/selectedTd.blade.php: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /src/Screen/Concerns/Multipliable.php: -------------------------------------------------------------------------------- 1 | set('multiple', 'multiple'); 17 | $this->set('allowEmpty', '1'); // TODO do NOT allow null value when multiple is on 18 | 19 | $this->inlineAttributes[] = 'multiple'; 20 | 21 | return $this->addBeforeRender(function () { 22 | $name = $this->get('name'); 23 | 24 | $this->set('name', Str::finish($name, '[]')); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Screen/Contracts/Searchable.php: -------------------------------------------------------------------------------- 1 | getHttpValue(); 15 | 16 | $builder->when($value['start'] ?? null, fn (Builder $query) => $query->whereDate($this->column, '>=', $value['start'])); 17 | $builder->when($value['end'] ?? null, fn (Builder $query) => $query->whereDate($this->column, '<=', $value['end'])); 18 | 19 | return $builder; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /resources/js/controllers/radiobutton_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | 3 | export default class extends ApplicationController { 4 | /** 5 | * 6 | */ 7 | checked(event) { 8 | event.target.offsetParent.querySelectorAll('input').forEach((input) => { 9 | input.removeAttribute('checked'); 10 | }); 11 | event.target.offsetParent.querySelectorAll('label').forEach((label) => { 12 | label.classList.remove('active'); 13 | }); 14 | event.target.classList.add('active'); 15 | event.target.setAttribute('checked', 'checked'); 16 | event.target.dispatchEvent(new Event("change")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Platform/Http/Controllers/IndexController.php: -------------------------------------------------------------------------------- 1 | route(config('platform.index')); 21 | } 22 | 23 | /** 24 | * Show the fallback view for undefined routes. 25 | */ 26 | public function fallback(): View 27 | { 28 | return view('platform::errors.404'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /resources/views/header.blade.php: -------------------------------------------------------------------------------- 1 | @push('head') 2 | 3 | 4 | 11 | 12 | 13 | 14 | @endpush 15 | 16 |
17 | @auth 18 | 19 | @endauth 20 | 21 |

22 | {{ config('app.name') }} 23 |

24 |
25 | -------------------------------------------------------------------------------- /resources/views/actions/modal.blade.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /database/migrations/2015_04_12_000000_create_orchid_users_table.php: -------------------------------------------------------------------------------- 1 | jsonb('permissions')->nullable(); 16 | }); 17 | } 18 | 19 | /** 20 | * Reverse the migrations. 21 | */ 22 | public function down(): void 23 | { 24 | Schema::table('users', function (Blueprint $table) { 25 | $table->dropColumn(['permissions']); 26 | }); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /database/seeders/OrchidDatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call([ 22 | // AttachmentsTableSeeder::class, 23 | // UsersTableSeeder::class, 24 | // RolesTableSeeder::class, 25 | // SettingsTableSeeder::class, 26 | ]); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/User/UserRoleLayout.php: -------------------------------------------------------------------------------- 1 | fromModel(Role::class, 'name') 24 | ->multiple() 25 | ->title(__('Name role')) 26 | ->help('Specify which groups this account should belong to'), 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Platform/Events/RemoveRoleEvent.php: -------------------------------------------------------------------------------- 1 | roles = collect($role); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /stubs/field.blade.stub: -------------------------------------------------------------------------------- 1 |
2 | merge([ 5 | 'data-{{ controller }}-target' => 'name', 6 | 'data-action' => 'input->{{ controller }}#greet', 7 | ]) 8 | }}> 9 | 10 | 11 |
12 | 13 | 27 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Columns.php: -------------------------------------------------------------------------------- 1 | layouts = $layouts; 28 | } 29 | 30 | /** 31 | * @return mixed 32 | */ 33 | public function build(Repository $repository) 34 | { 35 | return $this->buildAsDeep($repository); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/js/controllers/code_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | import CodeFlask from 'codeflask'; 3 | 4 | 5 | export default class extends ApplicationController { 6 | /** 7 | * 8 | */ 9 | connect() { 10 | const input = this.element.querySelector('input'); 11 | 12 | const flask = new CodeFlask(this.element.querySelector('.code'), { 13 | language: this.data.get('language'), 14 | lineNumbers: this.data.get('lineNumbers'), 15 | defaultTheme: this.data.get('defaultTheme'), 16 | readonly: input.readOnly, 17 | }); 18 | 19 | flask.updateCode(input.value); 20 | 21 | flask.onUpdate((code) => { 22 | input.value = code; 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Blank.php: -------------------------------------------------------------------------------- 1 | layouts = $layouts; 28 | } 29 | 30 | /** 31 | * @return \Illuminate\View\View|mixed 32 | */ 33 | public function build(Repository $repository) 34 | { 35 | return $this->buildAsDeep($repository); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /resources/views/actions/toggle.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 8 | 9 | 10 | 21 |
22 | -------------------------------------------------------------------------------- /src/Platform/Configuration/ManagesPackage.php: -------------------------------------------------------------------------------- 1 | getHttpValue().'%'; 17 | 18 | if (InstalledVersions::satisfies(new VersionParser, 'laravel/framework', '>11.17.0')) { 19 | return $builder->whereLike($this->column, $value); 20 | } 21 | 22 | /** 23 | * @deprecated logic for older Laravel versions 24 | */ 25 | return $builder->where($this->column, 'like', $value); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /resources/js/controllers/viewport-entrance-toggle_controller.js: -------------------------------------------------------------------------------- 1 | import { Controller } from '@hotwired/stimulus'; 2 | 3 | export default class extends Controller { 4 | initialize() { 5 | this.intersectionObserver = new IntersectionObserver((entries) => this.processIntersectionEntries(entries)); 6 | } 7 | 8 | connect() { 9 | this.intersectionObserver.observe(this.element); 10 | } 11 | 12 | disconnect() { 13 | this.intersectionObserver.unobserve(this.element); 14 | } 15 | 16 | // Private 17 | processIntersectionEntries(entries) { 18 | entries.forEach((entry) => { 19 | this.element.classList.toggle(this.data.get('class'), entry.isIntersecting && window.document.body.scrollHeight > window.document.body.clientHeight + 400); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /resources/views/partials/profile.blade.php: -------------------------------------------------------------------------------- 1 | 17 | -------------------------------------------------------------------------------- /resources/views/partials/search.blade.php: -------------------------------------------------------------------------------- 1 | @if(Dashboard::getSearch()->isNotEmpty()) 2 |
3 |
4 |
5 | 9 |
10 | 11 |
12 |
13 | 17 |
18 |
19 | @else 20 |
21 | @endif 22 | -------------------------------------------------------------------------------- /stubs/field.stub: -------------------------------------------------------------------------------- 1 | 'Enter text...', 23 | 'class' => 'form-control', 24 | 'type' => 'text', 25 | ]; 26 | 27 | /** 28 | * List of attributes available for the HTML tag. 29 | * 30 | * @var array 31 | */ 32 | protected $inlineAttributes = [ 33 | 'placeholder', 34 | 'value', 35 | 'type', 36 | 'name' 37 | ]; 38 | } 39 | -------------------------------------------------------------------------------- /routes/auth.php: -------------------------------------------------------------------------------- 1 | name('login'); 12 | Route::middleware('throttle:60,1') 13 | ->post('login', [LoginController::class, 'login']) 14 | ->name('login.auth'); 15 | 16 | Route::get('lock', [LoginController::class, 'resetCookieLockMe'])->name('login.lock'); 17 | } 18 | 19 | Route::get('switch-logout', [LoginController::class, 'switchLogout']); 20 | Route::post('switch-logout', [LoginController::class, 'switchLogout'])->name('switch.logout'); 21 | Route::post('logout', [LoginController::class, 'logout'])->name('logout'); 22 | -------------------------------------------------------------------------------- /resources/views/layouts/legend.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | @empty(!$title) 4 |
5 | 6 | {{ $title }} 7 | 8 |
9 | @endempty 10 | 11 |
12 | @foreach($columns as $column) 13 |
14 |
15 | {!! $column->buildDt($repository) !!} 16 |
17 |
18 | {!! $column->buildDd($repository) !!} 19 |
20 |
21 | @endforeach 22 |
23 |
24 | -------------------------------------------------------------------------------- /resources/views/fields/switch.blade.php: -------------------------------------------------------------------------------- 1 | @isset($sendTrueOrFalse) 2 | 3 |
4 | 9 | 10 |
11 | @else 12 |
13 | 17 | 18 |
19 | @endisset 20 | -------------------------------------------------------------------------------- /database/migrations/2015_10_19_214424_create_orchid_roles_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 16 | $table->string('slug')->unique(); 17 | $table->string('name'); 18 | $table->jsonb('permissions')->nullable(); 19 | $table->timestamps(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | */ 26 | public function down(): void 27 | { 28 | Schema::dropIfExists('roles'); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/Platform/Http/Controllers/SortableController.php: -------------------------------------------------------------------------------- 1 | input('model'); 19 | 20 | abort_unless(class_exists($classModel), 400); 21 | 22 | $model = new $classModel; 23 | 24 | $request->collect('items')->each(function ($item) use ($model) { 25 | $model->where($model->getKeyName(), '=', $item['id'])->update([ 26 | $model->getSortColumnName() => $item['sortOrder'], 27 | ]); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Platform/Events/AddRoleEvent.php: -------------------------------------------------------------------------------- 1 | roles = collect($role); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Screen/Fields/Label.php: -------------------------------------------------------------------------------- 1 | null, 30 | 'value' => null, 31 | ]; 32 | 33 | /** 34 | * Attributes available for a particular tag. 35 | * 36 | * @var array 37 | */ 38 | protected $inlineAttributes = [ 39 | 'class', 40 | ]; 41 | } 42 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/Examples/ExampleElements.php: -------------------------------------------------------------------------------- 1 | route('platform.example.fields'), 20 | 21 | Menu::make('Advanced Elements') 22 | ->route('platform.example.advanced'), 23 | 24 | Menu::make('Text Editors') 25 | ->route('platform.example.editors'), 26 | 27 | Menu::make('Run Actions') 28 | ->route('platform.example.actions'), 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /resources/views/components/notification.blade.php: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 14 | 15 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /resources/sass/app.scss: -------------------------------------------------------------------------------- 1 | // Core variables and mixins 2 | @import "theme/variables"; 3 | 4 | // Vendor 5 | @import "bootstrap/scss/bootstrap"; 6 | @import "dropzone/dist/basic"; 7 | @import "dropzone/dist/dropzone"; 8 | @import "cropperjs/dist/cropper"; 9 | @import "simplemde/dist/simplemde.min"; 10 | @import "flatpickr/dist/flatpickr.min"; 11 | @import "leaflet/dist/leaflet"; 12 | @import "quill/dist/quill.snow"; 13 | @import "frappe-charts/src/css/charts"; 14 | @import "tom-select/dist/scss/tom-select.bootstrap5"; 15 | 16 | // App 17 | @import "core/mixins"; 18 | @import "core/reset"; 19 | @import "core/layout"; 20 | @import "core/buttons"; 21 | @import "core/modals"; 22 | @import "plugins/plugin"; 23 | @import "core/utilities"; 24 | @import "core/tables"; 25 | @import "core/form"; 26 | @import "plugins/dropzone"; 27 | @import "plugins/load-opacity"; 28 | @import "plugins/accordion"; 29 | @import "plugins/tom-select"; 30 | -------------------------------------------------------------------------------- /resources/views/partials/fields/matrixRow.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @foreach($columns as $column) 3 | 4 | 5 | {!! 6 | $fields[$column] 7 | ->value($row[$column] ?? null) 8 | ->prefix($name) 9 | ->id("$idPrefix-$key-$column") 10 | ->name($keyValue ? $column : "[$key][$column]") 11 | !!} 12 | 13 | 14 | @if ($loop->last && $removableRows) 15 | 16 | 20 | 21 | 22 | 23 | @endif 24 | @endforeach 25 | 26 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/Examples/TabMenuExample.php: -------------------------------------------------------------------------------- 1 | route('platform.example.layouts'), 20 | 21 | Menu::make('Get Started') 22 | ->route('platform.main'), 23 | 24 | Menu::make('Documentation') 25 | ->url('https://orchid.software/en/docs'), 26 | 27 | Menu::make('Example Screen') 28 | ->route('platform.example') 29 | ->badge(fn () => 6), 30 | ]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /resources/views/partials/alert.blade.php: -------------------------------------------------------------------------------- 1 | @if (session()->has(\Orchid\Alert\Alert::SESSION_MESSAGE)) 2 |
3 | {!! session(\Orchid\Alert\Alert::SESSION_MESSAGE) !!} 4 | 5 | @yield('flash_notification.sub_message') 6 | 7 |
8 | @endif 9 | 10 | @empty(!$errors->count()) 11 | 20 | @endif 21 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/User/UserEditLayout.php: -------------------------------------------------------------------------------- 1 | type('text') 23 | ->max(255) 24 | ->required() 25 | ->title(__('Name')) 26 | ->placeholder(__('Name')), 27 | 28 | Input::make('user.email') 29 | ->type('email') 30 | ->required() 31 | ->title(__('Email')) 32 | ->placeholder(__('Email')), 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | import * as Turbo from '@hotwired/turbo'; 2 | import * as Bootstrap from 'bootstrap'; 3 | import { Application } from '@hotwired/stimulus'; 4 | import ApplicationController from './controllers/application_controller'; 5 | import Orchid from "./orchid"; 6 | import { registerControllers } from 'stimulus-vite-helpers'; 7 | 8 | window.Turbo = Turbo; 9 | window.Bootstrap = Bootstrap; 10 | window.application = Application.start(); 11 | window.Controller = ApplicationController; 12 | window.Orchid = Orchid; 13 | 14 | const controllers = import.meta.glob('./**/*_controller.js', { eager: true }); 15 | registerControllers(application, controllers); 16 | 17 | window.addEventListener('turbo:before-fetch-request', (event) => { 18 | let state = document.getElementById('screen-state')?.value; 19 | 20 | if (state && state.length > 0) { 21 | event.detail?.fetchOptions?.body?.append('_state', state); 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /resources/views/auth.blade.php: -------------------------------------------------------------------------------- 1 | @extends('platform::app') 2 | 3 | @section('body') 4 | 5 |
6 | 24 |
25 | 26 | @endsection 27 | -------------------------------------------------------------------------------- /resources/views/errors/404.blade.php: -------------------------------------------------------------------------------- 1 | @extends('platform::dashboard') 2 | 3 | @section('title', '404') 4 | @section('description', __("You requested a page that doesn't exist.")) 5 | 6 | @section('content') 7 | 8 |
9 |

10 | {{ __("Sorry, we don't have anything to show you on this page") }} 11 |

12 | 13 | 14 |

{{ __("This could be because:") }}

15 |
    16 |
  • {{ __("The item you're looking for has been deleted") }}
  • 17 |
  • {{ __("You don't have access to it") }}
  • 18 |
  • {{ __("You clicked a broken link") }}
  • 19 |
20 | 21 |

{{ __("If you think you should have access to this page, ask the person who manages the project (or the account) to add you to it.") }}

22 |
23 | 24 | @endsection 25 | -------------------------------------------------------------------------------- /resources/views/fields/select.blade.php: -------------------------------------------------------------------------------- 1 |
8 | 20 |
21 | -------------------------------------------------------------------------------- /resources/views/partials/layouts/filter.blade.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /resources/js/controllers/browsing_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | 3 | export default class extends ApplicationController { 4 | 5 | /** 6 | * 7 | */ 8 | connect() { 9 | // Selecting the iframe element 10 | var iframe = this.element.querySelector('iframe'); 11 | 12 | // Resize for SPA 13 | this.resizeTimer = setInterval(() => { 14 | // Set color background 15 | iframe.contentDocument.body.style.backgroundColor = 'initial'; 16 | iframe.contentDocument.body.style.overflow = 'hidden'; 17 | 18 | let body = iframe.contentWindow.document.body; 19 | 20 | iframe.contentDocument.body.style.height = 'inherit' 21 | iframe.style.height = Math.max(body.scrollHeight, body.offsetHeight) + 'px'; 22 | }, 100); 23 | } 24 | 25 | disconnect() { 26 | clearTimeout(this.resizeTimer); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /resources/js/controllers/button_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | 3 | export default class extends ApplicationController { 4 | 5 | /** 6 | * 7 | * @param event 8 | * @returns {boolean} 9 | */ 10 | confirm(event) { 11 | let button = this.element.outerHTML 12 | .replace('btn-link', 'btn-default') 13 | .replace(/data-action="(.*?)"/g, ''); 14 | 15 | this.application 16 | .getControllerForElementAndIdentifier(this.confirmModal, 'confirm') 17 | .open({ 18 | 'message': this.data.get('confirm'), 19 | 'button': button, 20 | }); 21 | 22 | event.preventDefault(); 23 | return false; 24 | } 25 | 26 | 27 | /** 28 | * 29 | * @returns {HTMLElement} 30 | */ 31 | get confirmModal() { 32 | return document.getElementById(`confirm-dialog`); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /resources/views/layouts/filter.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | @foreach ($filters as $filter) 4 |
5 | {!! $filter->render() !!} 6 |
7 | @endforeach 8 |
9 |
10 | 13 | 16 |
17 |
18 |
19 |
20 | 21 | -------------------------------------------------------------------------------- /src/Platform/Commands/PublishCommand.php: -------------------------------------------------------------------------------- 1 | call('vendor:publish', [ 35 | '--tag' => 'orchid-assets', 36 | '--force' => true, 37 | ]); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /resources/js/controllers/password_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | 3 | export default class extends ApplicationController { 4 | 5 | /** 6 | * 7 | * @type {string[]} 8 | */ 9 | static targets = [ 10 | 'password', 11 | 'iconShow', 12 | 'iconLock' 13 | ]; 14 | 15 | /** 16 | * 17 | */ 18 | change() { 19 | const currentType = this.passwordTarget.type; 20 | let type = 'password'; 21 | 22 | if(currentType === 'text'){ 23 | this.iconLockTarget.classList.add('none'); 24 | this.iconShowTarget.classList.remove('none'); 25 | } 26 | 27 | if (currentType === 'password') { 28 | type = 'text'; 29 | this.iconLockTarget.classList.remove('none'); 30 | this.iconShowTarget.classList.add('none'); 31 | } 32 | 33 | this.passwordTarget.setAttribute('type', type); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /stubs/listener.stub: -------------------------------------------------------------------------------- 1 | value, $this->tz)->translatedFormat($this->format); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Support/Names.php: -------------------------------------------------------------------------------- 1 | replace('.', $separator)->slug() 31 | : $prefix; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resources/views/fields/datetime.blade.php: -------------------------------------------------------------------------------- 1 |
5 | 11 | 12 | @if(true === $allowEmpty) 13 |
14 | 17 | 18 | 19 |
20 | @endif 21 | 22 | @foreach($quickDates as $name => $value) 23 | 26 | @endforeach 27 |
28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Screen/Components/Cells/Time.php: -------------------------------------------------------------------------------- 1 | value, $this->tz)->toTimeString($this->unitPrecision); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resources/views/partials/notification.blade.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /src/Support/Formats.php: -------------------------------------------------------------------------------- 1 | toDateTimeString(); 21 | } 22 | 23 | /** 24 | * Format bytes to KB, MB, GB, TB. 25 | */ 26 | public static function formatBytes(int $size, int $precision = 2): string 27 | { 28 | if ($size <= 0) { 29 | return (string) $size; 30 | } 31 | 32 | $base = log($size) / log(1024); 33 | $suffixes = [' bytes', ' KB', ' MB', ' GB', ' TB']; 34 | 35 | return round(1024 ** ($base - floor($base)), $precision).$suffixes[(int) floor($base)]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/User/UserPasswordLayout.php: -------------------------------------------------------------------------------- 1 | query->get('user'); 23 | 24 | $exists = $user->exists; 25 | 26 | $placeholder = $exists 27 | ? __('Leave empty to keep current password') 28 | : __('Enter the password to be set'); 29 | 30 | return [ 31 | Password::make('user.password') 32 | ->placeholder($placeholder) 33 | ->title(__('Password')) 34 | ->required(! $exists), 35 | ]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /stubs/screen.stub: -------------------------------------------------------------------------------- 1 | value, $this->decimals, $this->decimal_separator, $this->thousands_separator); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Screen/Layouts/View.php: -------------------------------------------------------------------------------- 1 | template = $template; 28 | $this->data = $data; 29 | } 30 | 31 | /** 32 | * @return mixed 33 | */ 34 | public function build(Repository $repository) 35 | { 36 | $this->query = $repository; 37 | 38 | if (! $this->isSee()) { 39 | return; 40 | } 41 | 42 | $data = array_merge($this->data, $repository->toArray()); 43 | 44 | return view($this->template, $data); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /resources/views/fields/checkbox.blade.php: -------------------------------------------------------------------------------- 1 |
3 | @isset($sendTrueOrFalse) 4 | 5 |
6 | 10 | 11 |
12 | @else 13 |
14 | 17 | 18 |
19 | @endisset 20 |
21 | 22 | -------------------------------------------------------------------------------- /src/Support/Facades/Alert.php: -------------------------------------------------------------------------------- 1 | value * 100, $this->decimals, $this->decimal_separator, $this->thousands_separator).'%'; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /resources/js/controllers/pull-to-refresh_controller.js: -------------------------------------------------------------------------------- 1 | import {Controller} from '@hotwired/stimulus'; 2 | 3 | export default class extends Controller { 4 | /** 5 | * 6 | * @param event 7 | */ 8 | touchstart(event) { 9 | this.startPageY = event.touches[0].screenY; 10 | } 11 | 12 | /** 13 | * 14 | * @param event 15 | */ 16 | touchmove(event) { 17 | 18 | if (this.willRefresh) { 19 | return 20 | } 21 | 22 | const scrollTop = document.body.scrollTop 23 | const dy = event.changedTouches[0].screenY - this.startPageY 24 | 25 | if (scrollTop < 1 && dy > 150) { 26 | this.willRefresh = true; 27 | this.element.style = 'filter: blur(1px);opacity: 0.2;touch-action: none;'; 28 | } 29 | } 30 | 31 | /** 32 | * 33 | * @param event 34 | */ 35 | touchend(event) { 36 | if (this.willRefresh) { 37 | Turbo.visit(window.location.toString(), {action: 'replace'}); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /resources/views/fields/numberRange.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 11 |
12 |
13 | 14 |
15 |
16 | 23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/Role/RoleEditLayout.php: -------------------------------------------------------------------------------- 1 | type('text') 23 | ->max(255) 24 | ->required() 25 | ->title(__('Name')) 26 | ->placeholder(__('Name')) 27 | ->help(__('Role display name')), 28 | 29 | Input::make('role.slug') 30 | ->type('text') 31 | ->max(255) 32 | ->required() 33 | ->title(__('Slug')) 34 | ->placeholder(__('Slug')) 35 | ->help(__('Actual name in the system')), 36 | ]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/Examples/ChartLineExample.php: -------------------------------------------------------------------------------- 1 | 1, 25 | 'regionFill' => 1, 26 | 'hideDots' => 0, 27 | 'hideLine' => 0, 28 | 'heatline' => 0, 29 | 'dotSize' => 3, 30 | ]; 31 | 32 | /** 33 | * To highlight certain values on the Y axis, markers can be set. 34 | * They will shown as dashed lines on the graph. 35 | */ 36 | protected function markers(): ?array 37 | { 38 | return [ 39 | [ 40 | 'label' => 'Medium', 41 | 'value' => 40, 42 | ], 43 | ]; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /database/migrations/2017_09_17_125801_create_notifications_table.php: -------------------------------------------------------------------------------- 1 | uuid('id')->primary(); 19 | $table->string('type'); 20 | $table->morphs('notifiable'); 21 | $table->text('data'); 22 | $table->timestamp('read_at')->nullable(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down(): void 34 | { 35 | Schema::dropIfExists('notifications'); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /stubs/filters.stub: -------------------------------------------------------------------------------- 1 | all(); 34 | } 35 | 36 | if (! is_array($array)) { 37 | return false; 38 | } 39 | 40 | return count($array) === count(array_filter($array, $callback)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /resources/views/auth/impersonation.blade.php: -------------------------------------------------------------------------------- 1 | @extends('platform::auth') 2 | @section('title',__('Access Denied: Viewing as Another User')) 3 | 4 | @section('content') 5 |

{{__('Limited Access')}}

6 | 7 |
13 | @csrf 14 | 15 |

16 | {{ __("You are currently viewing this page on behalf of a user who does not have access to it. To return to viewing as yourself, please click the 'Switch to My Account' button. It's possible that the page may be displayed correctly when viewed from your own account.") }} 17 |

18 | 19 | 22 | 23 |
24 | @endsection 25 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Tabs.php: -------------------------------------------------------------------------------- 1 | null, 25 | ]; 26 | 27 | /** 28 | * Layout constructor. 29 | * 30 | * @param Layout[] $layouts 31 | */ 32 | public function __construct(array $layouts = []) 33 | { 34 | $this->layouts = $layouts; 35 | } 36 | 37 | /** 38 | * @return mixed 39 | */ 40 | public function build(Repository $repository) 41 | { 42 | return $this->buildAsDeep($repository); 43 | } 44 | 45 | /** 46 | * @return $this 47 | */ 48 | public function activeTab(string $name) 49 | { 50 | $this->variables['activeTab'] = $name; 51 | 52 | return $this; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /resources/views/fields/relation.blade.php: -------------------------------------------------------------------------------- 1 |
17 | 22 |
23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Chernyaev Alexandr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Screen/Sight.php: -------------------------------------------------------------------------------- 1 | $this->column, 22 | 'title' => $this->title, 23 | 'popover' => $this->popover, 24 | ]); 25 | } 26 | 27 | /** 28 | * Builds content for the column. 29 | * 30 | * @param Repository|Model $repository 31 | * 32 | * @return string|\Illuminate\Contracts\Support\Htmlable|null 33 | */ 34 | public function buildDd($repository) 35 | { 36 | $value = $this->render 37 | ? $this->handler($repository) 38 | : $repository->getContent($this->name); 39 | 40 | return $this->render === null 41 | ? e($value) 42 | : $value; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /resources/views/layouts/metric.blade.php: -------------------------------------------------------------------------------- 1 |
2 | @isset($title) 3 | 4 | {{ __($title) }} 5 | 6 | @endisset 7 |
8 | @foreach($metrics as $key => $metric) 9 |
10 |
11 | {{ __($key) }} 12 |

13 | {{ is_array($metric) ? $metric['value'] : $metric }} 14 | 15 | @if(isset($metric['diff']) && (float)$metric['diff'] !== 0.0) 16 | 17 | {{ round($metric['diff'], 2) }} % 18 | 19 | @endif 20 |

21 |
22 |
23 | @endforeach 24 |
25 |
26 | -------------------------------------------------------------------------------- /src/Screen/Fields/Map.php: -------------------------------------------------------------------------------- 1 | 14, 35 | 'height' => '300px', 36 | ]; 37 | 38 | /** 39 | * Attributes available for a particular tag. 40 | * 41 | * @var array 42 | */ 43 | protected $inlineAttributes = [ 44 | 'name', 45 | 'required', 46 | 'height', 47 | ]; 48 | } 49 | -------------------------------------------------------------------------------- /src/Screen/Fields/NumberRange.php: -------------------------------------------------------------------------------- 1 | 'form-control', 28 | 'type' => 'number', 29 | ]; 30 | /** 31 | * Attributes available for a particular tag. 32 | * 33 | * @var array 34 | */ 35 | protected $inlineAttributes = [ 36 | 'form', 37 | 'name', 38 | 'class', 39 | 'min', 40 | 'max', 41 | 'pattern', 42 | 'readonly', 43 | 'step', 44 | 'type', 45 | ]; 46 | } 47 | -------------------------------------------------------------------------------- /resources/views/partials/confirm.blade.php: -------------------------------------------------------------------------------- 1 | 32 | 33 | -------------------------------------------------------------------------------- /src/Platform/Http/Requests/RelationRequest.php: -------------------------------------------------------------------------------- 1 | 'string|nullable', 20 | 'model' => 'string|required', 21 | 'key' => 'string|required', 22 | 'name' => 'string|required', 23 | 'scope' => 'string|nullable', 24 | 'append' => 'nullable', 25 | 'searchColumns' => 'string|nullable', 26 | ]; 27 | } 28 | 29 | /** 30 | * Prepare the data for validation. 31 | * 32 | * @return void 33 | */ 34 | protected function prepareForValidation() 35 | { 36 | $this->merge([ 37 | 'append' => $this->append, 38 | 'searchColumns' => $this->searchColumns, 39 | ]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Screen/Components/Cells/Boolean.php: -------------------------------------------------------------------------------- 1 | value = $value; 26 | $this->true = $true; 27 | $this->false = $false; 28 | } 29 | 30 | /** 31 | * Get the view/contents that represent the component. 32 | * 33 | * @return \Illuminate\Contracts\View\View|\Closure|string 34 | */ 35 | public function render() 36 | { 37 | $class = 'me-1 '.($this->value ? 'text-success' : 'text-danger'); 38 | $label = $this->value ? $this->true : $this->false; 39 | 40 | return "".$label; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "vite build" 5 | }, 6 | "dependencies": { 7 | "@babel/plugin-proposal-class-properties": "^7.13.0", 8 | "@babel/plugin-transform-block-scoping": "^7.12.1", 9 | "@babel/preset-env": "^7.13.15", 10 | "@hotwired/stimulus": "^3.1.0", 11 | "@hotwired/turbo": "^8.0.2", 12 | "@popperjs/core": "^2.9.2", 13 | "axios": "^1.1.3", 14 | "bootstrap": "^5.3.8", 15 | "codeflask": "^1.4.0", 16 | "cropperjs": "^1.5.11", 17 | "cross-env": "^10.1.0", 18 | "dropzone": "^5.9.2", 19 | "flatpickr": "^4.6.3", 20 | "frappe-charts": "^1.6.1", 21 | "inputmask": "^5.0.6", 22 | "laravel-vite-plugin": "^2.0.0", 23 | "leaflet": "^1.7.1", 24 | "postcss": "^8.2.10", 25 | "qs": "^6.14.0", 26 | "quill": "^2.0.0", 27 | "rtlcss": "^4.0.0", 28 | "sass": "^1.69.7", 29 | "sass-loader": "^16.0.5", 30 | "simplemde": "^1.11", 31 | "sortablejs": "^1.13.0", 32 | "stimulus-vite-helpers": "^3.0.1", 33 | "tom-select": "^2.3.1", 34 | "vite": "^7.1.9", 35 | "vite-plugin-manifest-sri": "^0.2.0", 36 | "vite-plugin-rtl-css": "^1.0.6" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Platform/Http/Layouts/NotificationTable.php: -------------------------------------------------------------------------------- 1 | cantHide() 27 | ->render(static fn ($notification) => view('platform::partials.notification', [ 28 | 'notification' => $notification, 29 | ])), 30 | ]; 31 | } 32 | 33 | public function textNotFound(): string 34 | { 35 | return __('No notifications'); 36 | } 37 | 38 | public function iconNotFound(): string 39 | { 40 | return 'bs.bell'; 41 | } 42 | 43 | public function subNotFound(): string 44 | { 45 | return __('You currently have no notifications, but maybe they will appear later.'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Platform/Configuration/ManagesModelOptions.php: -------------------------------------------------------------------------------- 1 | model($key, $default); 22 | 23 | return class_exists($model) ? new $model : $model; 24 | } 25 | 26 | /** 27 | * Get the class name for a given Dashboard model. 28 | */ 29 | public function model(string $key, ?string $default = null): string 30 | { 31 | return Arr::get($this->registeredReplaceModels, $key, $default ?? $key); 32 | } 33 | 34 | /** 35 | * Get the user model class name. 36 | */ 37 | public function useModel(string $key, string $custom): static 38 | { 39 | $this->registeredReplaceModels[$key] = $custom; 40 | 41 | return $this; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /database/migrations/2015_10_19_214425_create_orchid_role_users_table.php: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('user_id'); 16 | $table->unsignedInteger('role_id'); 17 | $table->primary(['user_id', 'role_id']); 18 | $table->foreign('user_id') 19 | ->references('id') 20 | ->on('users') 21 | ->onUpdate('cascade') 22 | ->onDelete('cascade'); 23 | $table->foreign('role_id') 24 | ->references('id') 25 | ->on('roles') 26 | ->onUpdate('cascade') 27 | ->onDelete('cascade'); 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | */ 34 | public function down(): void 35 | { 36 | Schema::dropIfExists('role_users'); 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /src/Platform/Commands/RowsCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('rows.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Layouts'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Platform/Commands/ChartCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('chart.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Layouts'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Platform/Commands/ScreenCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('screen.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Screens'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Platform/Commands/TableCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('table.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Layouts'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Platform/Commands/FilterCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('filters.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Filters'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Filters/BaseHttpEloquentFilter.php: -------------------------------------------------------------------------------- 1 | column]; 29 | } 30 | 31 | /** 32 | * Retrieves the value of the filter from the HTTP request. 33 | * 34 | * @return mixed The value of the filter input from the request, or null if not present. 35 | */ 36 | public function getHttpValue(): mixed 37 | { 38 | return $this->request->input('filter.'.$this->column); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Platform/Commands/TabMenuCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('tabMenu.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Layouts'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Platform/Commands/ListenerCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('listener.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Layouts'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /resources/js/controllers/input_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | import Inputmask from 'inputmask'; 3 | 4 | export default class extends ApplicationController { 5 | 6 | /** 7 | * 8 | * @returns {string|object} 9 | */ 10 | get mask() { 11 | let mask = this.data.get('mask'); 12 | 13 | try { 14 | mask = JSON.parse(mask); 15 | mask.autoUnmask = mask.autoUnmask || mask.removeMaskOnSubmit || undefined; 16 | 17 | return mask; 18 | } catch (e) { 19 | // as string 20 | return mask; 21 | } 22 | } 23 | 24 | /** 25 | * 26 | */ 27 | connect() { 28 | const element = this.element.querySelector('input'); 29 | let mask = this.mask; 30 | 31 | // mask 32 | if (mask.length < 1) { 33 | return; 34 | } 35 | 36 | let form = element.form || this.element.closest('form') 37 | 38 | form.addEventListener('orchid:screen-submit', () => { 39 | if (mask.removeMaskOnSubmit) { 40 | element.inputmask.remove(); 41 | } 42 | }); 43 | 44 | Inputmask(mask).mask(element); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Screen/AsMultiSource.php: -------------------------------------------------------------------------------- 1 | getBaseContent($field) ?? $this->getContentMultiLang($field, $locale); 29 | } 30 | 31 | /** 32 | * @param null $locale 33 | * 34 | * @return mixed 35 | */ 36 | private function getContentMultiLang(string $field, $locale = null) 37 | { 38 | $jsonContent = (array) $this->getAttribute($this->jsonColumnName); 39 | $fullName = ($locale ?? app()->getLocale()).'.'.$field; 40 | if (Arr::has($jsonContent, $fullName)) { 41 | return Arr::get($jsonContent, $fullName); 42 | } 43 | 44 | return Arr::get($jsonContent, config('app.fallback_locale').'.'.$field); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/User/ProfilePasswordLayout.php: -------------------------------------------------------------------------------- 1 | placeholder(__('Enter the current password')) 23 | ->title(__('Current password')) 24 | ->help('This is your password set at the moment.'), 25 | 26 | Password::make('password') 27 | ->placeholder(__('Enter the password to be set')) 28 | ->title(__('New password')), 29 | 30 | Password::make('password_confirmation') 31 | ->placeholder(__('Enter the password to be set')) 32 | ->title(__('Confirm new password')) 33 | ->help('A good password is at least 15 characters or at least 8 characters long, including a number and a lowercase letter.'), 34 | ]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Platform/Commands/PresenterCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('presenter.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Presenters'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Platform/Commands/SelectionCommand.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('selection.stub'); 39 | } 40 | 41 | /** 42 | * Get the default namespace for the class. 43 | * 44 | * @param string $rootNamespace 45 | */ 46 | protected function getDefaultNamespace($rootNamespace): string 47 | { 48 | return $rootNamespace.'\Orchid\Layouts'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Screen/Components/Popover.php: -------------------------------------------------------------------------------- 1 | content = $content; 32 | $this->placement = $placement; 33 | } 34 | 35 | /** 36 | * Get the view / contents that represent the component. 37 | * 38 | * @return View|string 39 | */ 40 | public function render() 41 | { 42 | return view('platform::components.popover'); 43 | } 44 | 45 | /** 46 | * Determine if the component should be rendered. 47 | * 48 | * @return bool 49 | */ 50 | public function shouldRender() 51 | { 52 | return ! empty($this->content); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /resources/js/controllers/confirm_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | import {Modal} from "bootstrap"; 3 | 4 | export default class extends ApplicationController { 5 | 6 | /** 7 | * 8 | * @type {[string, string]} 9 | */ 10 | static targets = ["message", "button"] 11 | 12 | /** 13 | * 14 | * @param message 15 | */ 16 | setMessage(message) { 17 | this.messageTarget.innerHTML = message; 18 | 19 | return this; 20 | } 21 | 22 | /** 23 | * 24 | * @param button 25 | */ 26 | setButton(button) { 27 | this.buttonTarget.innerHTML = button; 28 | 29 | return this; 30 | } 31 | 32 | /** 33 | * 34 | */ 35 | open(options) { 36 | this 37 | .setButton(options.button) 38 | .setMessage(options.message); 39 | 40 | /** 41 | * Added focus button for Mac OS firefox/safari 42 | */ 43 | document.querySelectorAll('button[type=submit]').forEach((button) => { 44 | button.addEventListener('click', (event) => { 45 | event.target.focus(); 46 | }); 47 | }); 48 | 49 | (new Modal(this.element)).show(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Content.php: -------------------------------------------------------------------------------- 1 | target = $target; 32 | } 33 | 34 | public function build(Repository $repository): string 35 | { 36 | $this->query = $repository; 37 | 38 | if (is_string($this->target) || is_array($this->target)) { 39 | $this->target = $repository->get($this->target, $this->target); 40 | } 41 | 42 | return (string) $this; 43 | } 44 | 45 | public function __toString(): string 46 | { 47 | if (method_exists($this, 'render')) { 48 | return (string) $this->render($this->target); 49 | } 50 | 51 | throw new \RuntimeException('Method render not found'); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Screen/Layouts/TabMenu.php: -------------------------------------------------------------------------------- 1 | query = $repository; 32 | 33 | $navigations = $this->navigations(); 34 | 35 | if (! $this->isSee() || empty($navigations)) { 36 | return; 37 | } 38 | 39 | $form = new Builder($navigations, $repository); 40 | 41 | return view($this->template, [ 42 | 'navigations' => $form->generateForm(), 43 | ]); 44 | } 45 | 46 | /** 47 | * Get the menu elements to be displayed. 48 | * 49 | * @return Menu[] 50 | */ 51 | abstract protected function navigations(): iterable; 52 | } 53 | -------------------------------------------------------------------------------- /resources/views/layouts/accordion.blade.php: -------------------------------------------------------------------------------- 1 |
2 | @foreach($manyForms as $name => $forms) 3 | @php 4 | $collapseId = 'collapse-' . \Illuminate\Support\Str::slug($name); 5 | $collapseIsOpen = in_array($name, $open); 6 | @endphp 7 | 8 | 17 | 18 | {!! $name !!} 19 | 20 | 21 |
28 | @foreach($forms as $form) 29 | {!! $form !!} 30 | @endforeach 31 |
32 | @endforeach 33 |
34 | -------------------------------------------------------------------------------- /resources/views/fields/dataRange.blade.php: -------------------------------------------------------------------------------- 1 |
5 |
6 |
7 | 14 |
15 |
16 | 17 |
18 |
19 | 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /database/factories/AttachmentFactory.php: -------------------------------------------------------------------------------- 1 | Str::random(), 29 | 'original_name' => Str::random(), 30 | 'mime' => 'unknown', 31 | 'extension' => 'unknown', 32 | 'size' => random_int(1, 100), 33 | 'sort' => random_int(1, 100), 34 | 'path' => Str::random(), 35 | 'description' => Str::random(), 36 | 'alt' => Str::random(), 37 | 'hash' => Str::random(), 38 | 'disk' => 'public', 39 | 'group' => null, 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Wrapper.php: -------------------------------------------------------------------------------- 1 | template = $template; 24 | $this->layouts = $layouts; 25 | } 26 | 27 | /** 28 | * @return \Illuminate\Contracts\View\View|void 29 | */ 30 | public function build(Repository $repository) 31 | { 32 | $this->query = $repository; 33 | 34 | if (! $this->isSee()) { 35 | return; 36 | } 37 | 38 | $build = collect($this->layouts) 39 | ->map(function ($layout, $key) use ($repository) { 40 | $items = $this->buildChild(Arr::wrap($layout), $key, $repository); 41 | 42 | return ! is_array($layout) ? reset($items)[0] : reset($items); 43 | }) 44 | ->merge($repository->all()) 45 | ->all(); 46 | 47 | return view($this->template, $build); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /resources/views/fields/matrix.blade.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | @foreach($columns as $key => $column) 10 | 13 | @endforeach 14 | 15 | 16 | 17 | 18 | @foreach($value as $key => $row) 19 | @include('platform::partials.fields.matrixRow',['row' => $row, 'key' => $key]) 20 | @endforeach 21 | 22 | 23 | 30 | 31 | 32 | 35 | 36 |
11 | {{ is_int($key) ? $column : $key }} 12 |
24 | 25 | 26 | 27 | {{ __($addRowLabel) }} 28 | 29 |
37 | -------------------------------------------------------------------------------- /src/Screen/Components/Cells/DateTimeSplit.php: -------------------------------------------------------------------------------- 1 | value, $this->tz); 34 | 35 | return sprintf('', 36 | $date->translatedFormat($this->upperFormat), 37 | $date->translatedFormat($this->lowerFormat), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Platform/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | middleware(static function ($request, $next) use ($permission) { 33 | if (Auth::user()->hasAccess($permission)) { 34 | return $next($request); 35 | } 36 | abort(403); 37 | }); 38 | 39 | abort_if(Auth::user() !== null && ! Auth::user()->hasAccess($permission), 403); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /resources/views/layouts/block.blade.php: -------------------------------------------------------------------------------- 1 |
2 | @if(!empty($title) || !empty($description)) 3 |
4 | 5 | {{ __($title ?? '') }} 6 | 7 | @if(!empty($description)) 8 |

9 | {!! __($description ?? '') !!} 10 |

11 | @endif 12 |
13 |
14 | @endif 15 |
16 | 17 |
18 | @foreach($manyForms as $key => $layouts) 19 | @foreach($layouts as $layout) 20 | {!! $layout ?? '' !!} 21 | @endforeach 22 | @endforeach 23 |
24 | 25 | @empty(!$commandBar) 26 |
27 | @foreach($commandBar as $command) 28 |
29 | {!! $command !!} 30 |
31 | @endforeach 32 |
33 | @endempty 34 |
35 |
36 | 37 | -------------------------------------------------------------------------------- /resources/views/partials/search-result.blade.php: -------------------------------------------------------------------------------- 1 | @forelse ($results as $group) 2 | 3 | @empty(!$group['label']) 4 |
5 | {{ $group['label'] }} 6 |
7 | @endempty 8 | 9 | @foreach ($group['result'] as $item) 10 |
11 | 12 | @empty(!$item->image()) 13 |
14 | {{ $item->title() }} 15 |
16 | @endempty 17 | 18 |
19 | 25 |
26 | {{ $item->subTitle() }} 27 |
28 |
29 |
30 | @endforeach 31 | 32 | @empty 33 |

34 | {{ __('There are no records in this view.') }} 35 |

36 | @endforelse 37 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Screens/PlatformScreen.php: -------------------------------------------------------------------------------- 1 | value, $this->decimals, $this->decimal_separator, $this->thousands_separator); 37 | 38 | return Str::of($value) 39 | ->prepend($this->before.' ') 40 | ->append(' '.$this->after) 41 | ->trim() 42 | ->toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Support/Testing/MakesHttpRequestsWrapper.php: -------------------------------------------------------------------------------- 1 | app; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Platform/Components/Notification.php: -------------------------------------------------------------------------------- 1 | user = $guard->user(); 25 | } 26 | 27 | /** 28 | * Get the view / contents that represent the component. 29 | * 30 | * @return View|string 31 | */ 32 | public function render() 33 | { 34 | $notifications = $this->user 35 | ->unreadNotifications() 36 | ->where('type', DashboardMessage::class) 37 | ->limit(15) 38 | ->get(); 39 | 40 | return view('platform::components.notification', [ 41 | 'notifications' => $notifications, 42 | ]); 43 | } 44 | 45 | /** 46 | * Determine if the component should be rendered. 47 | * 48 | * @return bool 49 | */ 50 | public function shouldRender(): bool 51 | { 52 | return config('platform.notifications.enabled', true); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Screen/Actions/DropDown.php: -------------------------------------------------------------------------------- 1 | 'btn btn-link icon-link gap-2', 33 | 'source' => null, 34 | 'icon' => null, 35 | 'list' => [], 36 | ]; 37 | 38 | /** 39 | * @param Actionable[] $list 40 | */ 41 | public function list(array $list): self 42 | { 43 | return $this->set('list', $list); 44 | } 45 | 46 | /** 47 | * @throws \Throwable 48 | * 49 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View|mixed 50 | */ 51 | public function build(?Repository $repository = null) 52 | { 53 | $this->set('source', $repository); 54 | 55 | return $this->render(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /resources/views/partials/layouts/th.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | @includeWhen($filter !== null, "platform::partials.layouts.filter", ['filter' => $filter]) 5 | 6 | @if($sort) 7 | 9 | {!! $title !!} 10 | 11 | 12 | 13 | @if(is_sort($column)) 14 | @php $sortIcon = get_sort($column) === 'desc' ? 'bs.sort-down' : 'bs.sort-up' @endphp 15 | 16 | @endif 17 | 18 | @else 19 | {!! $title !!} 20 | 21 | 22 | @endif 23 |
24 | 25 | @if($filterString) 26 | 35 | @endif 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/Screen/AsSource.php: -------------------------------------------------------------------------------- 1 | getAttribute($field); 31 | } 32 | 33 | return $this->getAttribute($field) // Try to get the field value from the object's attributes. 34 | ?? Arr::get($this->getRelations(), $field) // Try to get the field value from the object's relations. 35 | ?? Arr::get($this->attributesToArray(), $field); // Try to get the field value from the object's array representation. 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Metric.php: -------------------------------------------------------------------------------- 1 | labels = $labels; 34 | } 35 | 36 | /** 37 | * @return Factory|\Illuminate\View\View 38 | */ 39 | public function build(Repository $repository) 40 | { 41 | $this->query = $repository; 42 | 43 | if (! $this->isSee() || empty($this->labels)) { 44 | return; 45 | } 46 | 47 | $metrics = collect($this->labels)->map(fn (string $value) => $repository->getContent($value, '')); 48 | 49 | return view($this->template, [ 50 | 'title' => $this->title, 51 | 'metrics' => $metrics, 52 | ]); 53 | } 54 | 55 | /** 56 | * @return $this 57 | */ 58 | public function title(string $title): Metric 59 | { 60 | $this->title = $title; 61 | 62 | return $this; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Card.php: -------------------------------------------------------------------------------- 1 | commandBar = $commandBar; 35 | } 36 | 37 | public function render(Cardable $card): View 38 | { 39 | return view($this->template, [ 40 | 'title' => $card->title(), 41 | 'description' => $card->description(), 42 | 'image' => $card->image(), 43 | 'commandBar' => $this->buildCommandBar(), 44 | 'color' => $card->color()?->name(), 45 | ]); 46 | } 47 | 48 | private function buildCommandBar(): array 49 | { 50 | return collect($this->commandBar) 51 | ->map(fn (Actionable $command) => $command->build($this->query))->all(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Screen/Actions/Toggle.php: -------------------------------------------------------------------------------- 1 | 'form-check-input', 32 | 'type' => 'checkbox', 33 | 'novalidate' => false, 34 | 'method' => null, 35 | 'icon' => null, 36 | 'action' => null, 37 | 'confirm' => null, 38 | 'parameters' => [], 39 | 'turbo' => true, 40 | 'form' => 'post-form', 41 | 'status' => false, 42 | ]; 43 | 44 | public function __construct() 45 | { 46 | parent::__construct(); 47 | 48 | $this->addBeforeRender(function () { 49 | $this->set('placeholder', $this->get('title')); 50 | $this->set('title', null); 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Platform/Models/Role.php: -------------------------------------------------------------------------------- 1 | 'array', 41 | ]; 42 | 43 | /** 44 | * @var array 45 | */ 46 | protected $allowedFilters = [ 47 | 'id' => Where::class, 48 | 'name' => Like::class, 49 | 'slug' => Like::class, 50 | 'permissions' => Like::class, 51 | ]; 52 | 53 | /** 54 | * @var array 55 | */ 56 | protected $allowedSorts = [ 57 | 'id', 58 | 'name', 59 | 'slug', 60 | 'updated_at', 61 | 'created_at', 62 | ]; 63 | } 64 | -------------------------------------------------------------------------------- /src/Screen/Fields/Range.php: -------------------------------------------------------------------------------- 1 | display = $value; 37 | 38 | return $this; 39 | } 40 | 41 | /** 42 | * Check if the element is visible. 43 | * 44 | * This method returns the current visibility status of the component. 45 | * 46 | * @return bool `true` if the element is visible, `false` if it is hidden. 47 | */ 48 | public function isSee(): bool 49 | { 50 | return $this->display; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Attachment/Attachable.php: -------------------------------------------------------------------------------- 1 | attachments($group); 29 | } 30 | 31 | /** 32 | * Get all the attachments associated with the given model. 33 | * 34 | * @param string|null $group 35 | * 36 | * @return MorphToMany 37 | */ 38 | public function attachments(?string $group = null): MorphToMany 39 | { 40 | return $this->morphToMany( 41 | Dashboard::model(Attachment::class), 42 | 'attachmentable', 43 | 'attachmentable', 44 | 'attachmentable_id', 45 | 'attachment_id' 46 | ) 47 | ->when($group !== null, fn ($query) => $query->where('group', $group)) 48 | ->orderBy('sort'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Attachment/Contracts/Engine.php: -------------------------------------------------------------------------------- 1 | {$this->getSortColumnName()}; 27 | } 28 | 29 | /** 30 | * Set the sort column value. 31 | * 32 | * @param int $sortOrder The new sort column value. 33 | * 34 | * @return $this 35 | */ 36 | public function setSortColumn(int $sortOrder): static 37 | { 38 | $this->{$this->getSortColumnName()} = $sortOrder; 39 | 40 | return $this; 41 | } 42 | 43 | /** 44 | * Scope a query to sort the results by the sort column. 45 | * 46 | * @param \Illuminate\Database\Eloquent\Builder $query 47 | * @param string $direction The sorting direction (ASC or DESC). Default is ASC. 48 | * 49 | * @return \Illuminate\Database\Eloquent\Builder 50 | */ 51 | public function scopeSorted($query, $direction = 'ASC') 52 | { 53 | $column = $this->getSortColumnName(); 54 | 55 | return $query->orderBy($column, $direction); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Platform/ItemPermission.php: -------------------------------------------------------------------------------- 1 | group = $group; 38 | 39 | return $item; 40 | } 41 | 42 | /** 43 | * Add a permission to the permission group. 44 | * 45 | * @param string $slug The slug of the permission. 46 | * @param string $name The description of the permission. 47 | * 48 | * @return $this The current permission group instance. 49 | */ 50 | public function addPermission(string $slug, string $name): self 51 | { 52 | $this->items[] = [ 53 | 'slug' => $slug, 54 | 'description' => $name, 55 | ]; 56 | 57 | return $this; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /resources/views/actions/menu.blade.php: -------------------------------------------------------------------------------- 1 | @isset($title) 2 | 5 | @endisset 6 | 7 | @if (!empty($name)) 8 | 23 | @endif 24 | 25 | @if(!empty($list)) 26 | 41 | @endif 42 | 43 | @if($divider) 44 |
  • 45 | @endif 46 | 47 | -------------------------------------------------------------------------------- /stubs/app/Orchid/Layouts/Role/RoleListLayout.php: -------------------------------------------------------------------------------- 1 | sort() 29 | ->cantHide() 30 | ->filter(Input::make()) 31 | ->render(fn (Role $role) => Link::make($role->name) 32 | ->route('platform.systems.roles.edit', $role->id)), 33 | 34 | TD::make('slug', __('Slug')) 35 | ->sort() 36 | ->cantHide() 37 | ->filter(Input::make()), 38 | 39 | TD::make('created_at', __('Created')) 40 | ->usingComponent(DateTimeSplit::class) 41 | ->align(TD::ALIGN_RIGHT) 42 | ->defaultHidden() 43 | ->sort(), 44 | 45 | TD::make('updated_at', __('Last edit')) 46 | ->usingComponent(DateTimeSplit::class) 47 | ->align(TD::ALIGN_RIGHT) 48 | ->sort(), 49 | ]; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /resources/views/fields/map.blade.php: -------------------------------------------------------------------------------- 1 |
    5 |
    6 | 7 |
    8 |
    9 |
    10 | 11 | 17 |
    18 |
    19 | 20 | 27 |
    28 |
    29 | 30 | 34 |
    35 |
    36 | 37 |
    38 | 39 |
    40 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Component.php: -------------------------------------------------------------------------------- 1 | component = $component; 29 | } 30 | 31 | /** 32 | * @throws \Illuminate\Contracts\Container\BindingResolutionException 33 | * 34 | * @return mixed 35 | */ 36 | public function build(Repository $repository) 37 | { 38 | $this->query = $repository; 39 | 40 | if (! $this->isSee()) { 41 | return; 42 | } 43 | 44 | $data = array_merge($repository->toArray(), $this->data); 45 | 46 | $component = Blade::resolveComponent($this->component, $data); 47 | 48 | if (! $component->shouldRender()) { 49 | return; 50 | } 51 | 52 | $resolve = $component->resolveView(); 53 | 54 | $view = is_string($resolve) ? view($resolve) : $resolve; 55 | 56 | return $view->with($component->data()); 57 | } 58 | 59 | public function with(array $data): self 60 | { 61 | $this->data = array_merge($this->data, $data); 62 | 63 | return $this; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Screen/Components/Cells/Text.php: -------------------------------------------------------------------------------- 1 | 36 | @empty(!$title){{ $title }}@endempty 37 | {{ $text }}', [ 38 | 'class' => $this->clamp ? 'line-clamp-'.$this->clamp : '', 39 | 'title' => $this->title ? Str::of($this->value->getContent($this->title))->words($this->words) : '', 40 | 'text' => Str::of($this->value->getContent($this->text))->words($this->words), 41 | ]); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Rows.php: -------------------------------------------------------------------------------- 1 | query = $repository; 44 | 45 | if (! $this->isSee()) { 46 | return; 47 | } 48 | 49 | $form = new Builder($this->fields(), $repository); 50 | 51 | return view($this->template, [ 52 | 'form' => $form->generateForm(), 53 | 'title' => $this->title, 54 | ]); 55 | } 56 | 57 | public function title(?string $title = null): self 58 | { 59 | $this->title = $title; 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * @return iterable|iterable 66 | */ 67 | abstract protected function fields(): iterable; 68 | } 69 | -------------------------------------------------------------------------------- /src/Screen/Layouts/Selection.php: -------------------------------------------------------------------------------- 1 | query = $repository; 38 | 39 | if (! $this->isSee()) { 40 | return; 41 | } 42 | 43 | $filters = collect($this->filters()) 44 | ->map(static fn ($filter) => is_string($filter) ? resolve($filter) : $filter) 45 | ->filter(fn (Filter $filter) => $filter->isDisplay()); 46 | 47 | if ($filters->isEmpty()) { 48 | return; 49 | } 50 | 51 | return view($this->template, [ 52 | 'filters' => $filters, 53 | 'chunk' => ceil($filters->count() / 4), 54 | ]); 55 | } 56 | 57 | /** 58 | * @return Filter[] 59 | */ 60 | abstract public function filters(): iterable; 61 | } 62 | -------------------------------------------------------------------------------- /src/Support/Locale.php: -------------------------------------------------------------------------------- 1 | getLocale(); 41 | 42 | return in_array($locale, self::RTL) ? 'rtl' : 'ltr'; 43 | } 44 | 45 | /** 46 | * Check if the current or given locale has RTL direction. 47 | * 48 | * @param string|null $locale 49 | * 50 | * @return bool 51 | */ 52 | public static function isRtl(?string $locale = null): bool 53 | { 54 | $locale ??= app()->getLocale(); 55 | 56 | return self::currentDir($locale) === 'rtl'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /resources/js/controllers/toast_controller.js: -------------------------------------------------------------------------------- 1 | import ApplicationController from "./application_controller"; 2 | import {Toast} from "bootstrap"; 3 | 4 | export default class extends ApplicationController { 5 | 6 | /** 7 | * 8 | */ 9 | connect() { 10 | if (!('content' in document.createElement('template'))) { 11 | console.warn('Your browser does not support