├── .github ├── FUNDING.yml └── workflows │ └── phpunit.yml ├── LICENSE ├── README.md ├── composer.json ├── config └── easy_panel_config.php ├── database └── migrations │ ├── cruds_table.php │ └── panel_admins_table.php ├── resources ├── assets │ ├── css │ │ ├── fonts │ │ │ ├── Gilmer-Bold.eot │ │ │ ├── Gilmer-Bold.otf │ │ │ ├── Gilmer-Bold.svg │ │ │ ├── Gilmer-Bold.ttf │ │ │ ├── Gilmer-Bold.woff │ │ │ ├── Gilmer-Heavy.eot │ │ │ ├── Gilmer-Heavy.otf │ │ │ ├── Gilmer-Heavy.svg │ │ │ ├── Gilmer-Heavy.ttf │ │ │ ├── Gilmer-Heavy.woff │ │ │ ├── Gilmer-Medium.eot │ │ │ ├── Gilmer-Medium.otf │ │ │ ├── Gilmer-Medium.svg │ │ │ ├── Gilmer-Medium.ttf │ │ │ ├── Gilmer-Medium.woff │ │ │ ├── Gilmer-Regular.eot │ │ │ ├── Gilmer-Regular.otf │ │ │ ├── Gilmer-Regular.svg │ │ │ ├── Gilmer-Regular.ttf │ │ │ ├── Gilmer-Regular.woff │ │ │ ├── TofinoPersonal-Book.eot │ │ │ ├── TofinoPersonal-Book.otf │ │ │ ├── TofinoPersonal-Book.svg │ │ │ ├── TofinoPersonal-Book.ttf │ │ │ ├── TofinoPersonal-Book.woff │ │ │ ├── TofinoPersonal-Medium.eot │ │ │ ├── TofinoPersonal-Medium.otf │ │ │ ├── TofinoPersonal-Medium.svg │ │ │ ├── TofinoPersonal-Medium.ttf │ │ │ ├── TofinoPersonal-Medium.woff │ │ │ ├── TofinoPersonal-Regular.eot │ │ │ ├── TofinoPersonal-Regular.otf │ │ │ ├── TofinoPersonal-Regular.svg │ │ │ ├── TofinoPersonal-Regular.ttf │ │ │ └── TofinoPersonal-Regular.woff │ │ ├── icons │ │ │ ├── font-awesome │ │ │ │ ├── css │ │ │ │ │ ├── fa-brands.css │ │ │ │ │ ├── fa-brands.min.css │ │ │ │ │ ├── fa-regular.css │ │ │ │ │ ├── fa-regular.min.css │ │ │ │ │ ├── fa-solid.css │ │ │ │ │ ├── fa-solid.min.css │ │ │ │ │ ├── fontawesome-all.css │ │ │ │ │ ├── fontawesome-all.min.css │ │ │ │ │ ├── fontawesome.css │ │ │ │ │ └── fontawesome.min.css │ │ │ │ ├── less │ │ │ │ │ ├── _animated.less │ │ │ │ │ ├── _bordered-pulled.less │ │ │ │ │ ├── _core.less │ │ │ │ │ ├── _fixed-width.less │ │ │ │ │ ├── _icons.less │ │ │ │ │ ├── _larger.less │ │ │ │ │ ├── _list.less │ │ │ │ │ ├── _mixins.less │ │ │ │ │ ├── _rotated-flipped.less │ │ │ │ │ ├── _screen-reader.less │ │ │ │ │ ├── _stacked.less │ │ │ │ │ ├── _variables.less │ │ │ │ │ ├── fa-brands.less │ │ │ │ │ ├── fa-regular.less │ │ │ │ │ ├── fa-solid.less │ │ │ │ │ └── fontawesome.less │ │ │ │ ├── scss │ │ │ │ │ ├── _animated.scss │ │ │ │ │ ├── _bordered-pulled.scss │ │ │ │ │ ├── _core.scss │ │ │ │ │ ├── _fixed-width.scss │ │ │ │ │ ├── _icons.scss │ │ │ │ │ ├── _larger.scss │ │ │ │ │ ├── _list.scss │ │ │ │ │ ├── _mixins.scss │ │ │ │ │ ├── _rotated-flipped.scss │ │ │ │ │ ├── _screen-reader.scss │ │ │ │ │ ├── _stacked.scss │ │ │ │ │ ├── _variables.scss │ │ │ │ │ ├── fa-brands.scss │ │ │ │ │ ├── fa-regular.scss │ │ │ │ │ ├── fa-solid.scss │ │ │ │ │ └── fontawesome.scss │ │ │ │ └── webfonts │ │ │ │ │ ├── fa-brands-400.eot │ │ │ │ │ ├── fa-brands-400.svg │ │ │ │ │ ├── fa-brands-400.ttf │ │ │ │ │ ├── fa-brands-400.woff │ │ │ │ │ ├── fa-brands-400.woff2 │ │ │ │ │ ├── fa-regular-400.eot │ │ │ │ │ ├── fa-regular-400.svg │ │ │ │ │ ├── fa-regular-400.ttf │ │ │ │ │ ├── fa-regular-400.woff │ │ │ │ │ ├── fa-regular-400.woff2 │ │ │ │ │ ├── fa-solid-900.eot │ │ │ │ │ ├── fa-solid-900.svg │ │ │ │ │ ├── fa-solid-900.ttf │ │ │ │ │ ├── fa-solid-900.woff │ │ │ │ │ └── fa-solid-900.woff2 │ │ │ ├── simple-line-icons │ │ │ │ ├── css │ │ │ │ │ └── simple-line-icons.css │ │ │ │ ├── fonts │ │ │ │ │ ├── Simple-Line-Icons.eot │ │ │ │ │ ├── Simple-Line-Icons.svg │ │ │ │ │ ├── Simple-Line-Icons.ttf │ │ │ │ │ ├── Simple-Line-Icons.woff │ │ │ │ │ └── Simple-Line-Icons.woff2 │ │ │ │ ├── less │ │ │ │ │ └── simple-line-icons.less │ │ │ │ └── scss │ │ │ │ │ └── simple-line-icons.scss │ │ │ └── themify-icons │ │ │ │ ├── fonts │ │ │ │ ├── themify.eot │ │ │ │ ├── themify.svg │ │ │ │ ├── themify.ttf │ │ │ │ └── themify.woff │ │ │ │ ├── ie7 │ │ │ │ ├── ie7.css │ │ │ │ └── ie7.js │ │ │ │ ├── themify-icons.css │ │ │ │ └── themify-icons.less │ │ ├── rtl.css │ │ └── style.min.css │ └── js │ │ ├── app-style-switcher.min.js │ │ ├── bootstrap.min.js │ │ ├── ckeditor.min.js │ │ ├── custom.min.js │ │ ├── feather.min.js │ │ ├── jquery.min.js │ │ ├── perfect-scrollbar.jquery.min.js │ │ ├── popper.min.js │ │ └── sidebarmenu.min.js ├── lang │ ├── en_panel.json │ └── fa_panel.json └── views │ ├── components │ └── crud-menu-item.blade.php │ ├── home.blade.php │ ├── layouts │ ├── app.blade.php │ ├── child-sidebar-menu.blade.php │ └── sidebar.blade.php │ └── livewire │ ├── admins │ ├── create.blade.php │ ├── lists.blade.php │ ├── single.blade.php │ └── update.blade.php │ ├── crud │ ├── create.blade.php │ ├── lists.blade.php │ └── single.blade.php │ ├── role │ ├── create.blade.php │ ├── lists.blade.php │ ├── single.blade.php │ └── update.blade.php │ └── translation │ └── manage.blade.php └── src ├── Commands ├── Actions │ ├── DeleteCRUD.php │ ├── Install.php │ ├── MakeCRUD.php │ ├── MakeCRUDConfig.php │ ├── Migration.php │ ├── PublishStubs.php │ ├── Reinstall.php │ └── Uninstall.php ├── CRUDActions │ ├── CommandBase.php │ ├── MakeCreate.php │ ├── MakeRead.php │ ├── MakeSingle.php │ └── MakeUpdate.php ├── UserActions │ ├── DeleteAdmin.php │ ├── GetAdmins.php │ └── MakeAdmin.php └── stub │ ├── blade │ ├── create.blade.stub │ ├── read.blade.stub │ ├── single.blade.stub │ └── update.blade.stub │ ├── create.stub │ ├── crud.stub │ ├── read.stub │ ├── single.stub │ └── update.stub ├── Concerns └── Translatable.php ├── Contracts └── CRUDComponent.php ├── EasyPanelServiceProvider.php ├── Http ├── Livewire │ ├── Admins │ │ ├── Create.php │ │ ├── Lists.php │ │ ├── Single.php │ │ └── Update.php │ ├── CRUD │ │ ├── Create.php │ │ ├── Lists.php │ │ └── Single.php │ ├── Role │ │ ├── Create.php │ │ ├── Lists.php │ │ ├── Single.php │ │ └── Update.php │ └── Translation │ │ └── Manage.php └── Middleware │ ├── LangChanger.php │ └── isAdmin.php ├── Models ├── CRUD.php └── PanelAdmin.php ├── Parsers ├── Fields │ ├── Field.php │ └── stubs │ │ ├── badge.stub │ │ ├── bool-badge.stub │ │ ├── image.stub │ │ ├── linked-image.stub │ │ ├── text.stub │ │ └── titles │ │ ├── not-sortable.stub │ │ └── sortable.stub ├── HTMLInputs │ ├── BaseInput.php │ ├── Checkbox.php │ ├── Ckeditor.php │ ├── Date.php │ ├── DateTime.php │ ├── Email.php │ ├── File.php │ ├── InputList.php │ ├── MultiSelect.php │ ├── Number.php │ ├── Password.php │ ├── Select.php │ ├── Text.php │ ├── Textarea.php │ ├── Time.php │ └── stubs │ │ ├── checkbox.stub │ │ ├── ckeditor.stub │ │ ├── date.stub │ │ ├── datetime.stub │ │ ├── email.stub │ │ ├── file.stub │ │ ├── multi-select-provider.stub │ │ ├── multi-select.stub │ │ ├── number.stub │ │ ├── password.stub │ │ ├── select-provider.stub │ │ ├── select.stub │ │ ├── text.stub │ │ ├── textarea.stub │ │ └── time.stub └── StubParser.php ├── Services └── LangService.php ├── Support ├── Auth │ └── AdminIdentifier.php ├── Contract │ ├── AuthFacade.php │ ├── BaseFacade.php │ ├── LangManager.php │ └── UserProviderFacade.php └── User │ └── UserProvider.php ├── ViewComponents └── CrudMenuItem.php ├── helpers.php └── routes.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: rezaamini-ir 4 | custom: https://zarinp.al/rezaamini 5 | -------------------------------------------------------------------------------- /.github/workflows/phpunit.yml: -------------------------------------------------------------------------------- 1 | name: PHP Composer 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | run-tests: 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest] 19 | php: [7.3, 7.4, 8.0, 8.1] 20 | 21 | runs-on: ${{ matrix.os }} 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | 26 | - name: Validate composer.json and composer.lock 27 | run: composer validate --strict 28 | 29 | - name: Cache Composer packages 30 | id: composer-cache 31 | uses: actions/cache@v3 32 | with: 33 | path: vendor 34 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 35 | restore-keys: | 36 | ${{ runner.os }}-php- 37 | 38 | - name: Install dependencies 39 | run: composer install --prefer-dist --no-progress 40 | - name: Run Tests 41 | run: vendor/bin/phpunit 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Reza Amini 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/rezaamini-ir/laravel-easypanel/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/rezaamini-ir/laravel-easypanel/?branch=master) 2 | [![Build Status](https://scrutinizer-ci.com/g/rezaamini-ir/laravel-easypanel/badges/build.png?b=master)](https://scrutinizer-ci.com/g/rezaamini-ir/laravel-easypanel/build-status/master) 3 | 4 | # EasyPanel 5 | EasyPanel is a beautiful, customizable and flexible admin panel based on Livewire for Laravel. 6 | 7 | ![EasyPanel screenshots](https://easypanel.netlify.app/easypanel.png) 8 | 9 | 10 | ## Installation and Usage Guide: 11 | To see how to install EasyPanel and use it, please checkout the documentation of package: 12 | 13 | [EasyPanel Document](https://easypanel.netlify.app/getting-started) 14 | 15 | ### Features: 16 | - Easy to install 🚀 17 | - Multi Language 18 | - A tons of features for Fields & Inputs 19 | - RTL and LTR style 20 | - Support CKEditor and Persian Font for RTL mode 21 | - CRUD Maker GUI! 💡 22 | - Everything is customizable 23 | - A beautiful UI/UX with AdminMart template 24 | - UserProviders and Authentication classes are customizable and you can change them 25 | - Real time validation with Livewire 🚦 26 | - Control your admins using ACL System in GUI 27 | 28 | 29 | ## What do we use in this package? 30 | - [AdminMart Template](https://adminmart.com/) 31 | - [Livewire](https://github.com/livewire/livewire) 32 | - [Laravel EasyBlade](https://github.com/rezaamini-ir/laravel-easyblade) 33 | - [CKEditor 5](https://github.com/ckeditor/ckeditor5) 34 | - [Vazir Font](https://github.com/rastikerdar/vazir-font) 35 | - [Dynamic Acl](https://github.com/iya30n/dynamic-acl) 36 | 37 | ## Contribution: 38 | If you feel you can improve our package You are free to send a pull request or submit an issue :) 39 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rezaamini-ir/laravel-easypanel", 3 | "license": "MIT", 4 | "description": "An admin panel based on livewire", 5 | "authors": [ 6 | { 7 | "name": "Reza Amini", 8 | "email": "rezaaminiroyal@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": "^7.3|^8.0", 13 | "illuminate/support": "^8.0|^9.0|^10.0", 14 | "rezaamini-ir/laravel-easyblade" : "^0.5|^1.0", 15 | "laravel/framework": "^8.0|^9.0|^10.0", 16 | "livewire/livewire": "^1.0|^2.3", 17 | "iya30n/dynamic-acl": "^1.0" 18 | }, 19 | "require-dev": { 20 | "orchestra/testbench": "~3.7|^4.0|^5.0|^6.0" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "EasyPanel\\" : "src/" 25 | }, 26 | "files": ["src/helpers.php"] 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "EasyPanelTest\\" : "tests/" 31 | } 32 | }, 33 | 34 | "extra": { 35 | "laravel" : { 36 | "providers" : [ 37 | "EasyPanel\\EasyPanelServiceProvider" 38 | ] 39 | } 40 | }, 41 | "minimum-stability": "dev", 42 | "prefer-stable": true 43 | } 44 | -------------------------------------------------------------------------------- /config/easy_panel_config.php: -------------------------------------------------------------------------------- 1 | true, 11 | 12 | // RTL Style , If you are using a language like Persian or Arabic change it true 13 | 'rtl_mode' => false, 14 | 15 | // Package Language 16 | 'lang' => 'en', 17 | 18 | // Your user Model 19 | 'user_model' => file_exists(app_path('User.php')) ? App\User::class : App\Models\User::class, 20 | 21 | // set default guard to authenticate admins 22 | 'auth_guard' => config('auth.defaults.guard') ?? 'web', 23 | 24 | // How to authenticate admin 25 | // You may use other ways to authenticate a admin (tables or ..) you can manage it with this class 26 | 'auth_class' => AdminIdentifier::class, 27 | 28 | // With this class you can manage how to create a admin or remove it. 29 | 'admin_provider_class' => UserProvider::class, 30 | 31 | //The namespace of lang manager class 32 | 'lang_manager_class' => LangService::class, 33 | 34 | // it's a place where a user if not authenticated will be redirected 35 | 'redirect_unauthorized' => '/', 36 | 37 | // Admin panel routes prefix 38 | 'route_prefix' => 'admin', // http://localhost/admin 39 | 40 | // Your own middlewares for easy panel routes. 41 | 'additional_middlewares' => [], 42 | 43 | // Count of pagination in CRUD lists 44 | 'pagination_count' => 20, 45 | 46 | // Lazy validation for Livewire components 47 | 'lazy_mode' => true, 48 | 49 | // database configure 50 | 'database' => [ 51 | 'connection' => env('EASY_PANEL_DB_CONNECTION', env('DB_CONNECTION', 'mysql')), 52 | 'panel_admin_table' => 'panel_admins', 53 | 'crud_table' => 'cruds' 54 | ] 55 | ]; 56 | -------------------------------------------------------------------------------- /database/migrations/cruds_table.php: -------------------------------------------------------------------------------- 1 | id(); 26 | $table->string('name')->unique(); 27 | $table->string('model')->unique(); 28 | $table->string('route')->unique(); 29 | $table->string('icon')->default('fas fa-bars'); 30 | $table->boolean('active')->default(true); 31 | $table->boolean('built')->default(false); 32 | $table->boolean('with_acl')->default(false); 33 | $table->boolean('with_policy')->default(false); 34 | $table->timestamps(); 35 | }); 36 | } 37 | 38 | /** 39 | * Reverse the migrations. 40 | * 41 | * @return void 42 | */ 43 | public function down() 44 | { 45 | Schema::dropIfExists(config('easy_panel.database.crud_table')); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /database/migrations/panel_admins_table.php: -------------------------------------------------------------------------------- 1 | id(); 26 | $table->foreignId('user_id')->constrained(); 27 | $table->boolean('is_superuser'); 28 | $table->timestamps(); 29 | 30 | $table->unique(['user_id']); 31 | }); 32 | } 33 | 34 | /** 35 | * Reverse the migrations. 36 | * 37 | * @return void 38 | */ 39 | public function down() 40 | { 41 | Schema::dropIfExists(config('easy_panel.database.panel_admin_table')); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Bold.eot -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Bold.otf -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Bold.ttf -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Bold.woff -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Heavy.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Heavy.eot -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Heavy.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Heavy.otf -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Heavy.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Heavy.ttf -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Heavy.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Heavy.woff -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Medium.eot -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Medium.otf -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Medium.ttf -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Medium.woff -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Regular.eot -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Regular.otf -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Regular.ttf -------------------------------------------------------------------------------- /resources/assets/css/fonts/Gilmer-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/Gilmer-Regular.woff -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Book.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Book.eot -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Book.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Book.otf -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Book.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Book.ttf -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Book.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Book.woff -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Medium.eot -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Medium.otf -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Medium.ttf -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Medium.woff -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Regular.eot -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Regular.otf -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Regular.ttf -------------------------------------------------------------------------------- /resources/assets/css/fonts/TofinoPersonal-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/fonts/TofinoPersonal-Regular.woff -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/css/fa-brands.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Brands'; 7 | font-style: normal; 8 | font-weight: normal; 9 | src: url("../webfonts/fa-brands-400.eot"); 10 | src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); } 11 | 12 | .fab { 13 | font-family: 'Font Awesome 5 Brands'; } 14 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/css/fa-brands.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face{font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:Font Awesome\ 5 Brands} -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/css/fa-regular.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free'; 7 | font-style: normal; 8 | font-weight: 400; 9 | src: url("../webfonts/fa-regular-400.eot"); 10 | src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); } 11 | 12 | .far { 13 | font-family: 'Font Awesome 5 Free'; 14 | font-weight: 400; } 15 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/css/fa-regular.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:Font Awesome\ 5 Free;font-weight:400} -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/css/fa-solid.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free'; 7 | font-style: normal; 8 | font-weight: 900; 9 | src: url("../webfonts/fa-solid-900.eot"); 10 | src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); } 11 | 12 | .fa, 13 | .fas { 14 | font-family: 'Font Awesome 5 Free'; 15 | font-weight: 900; } 16 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/css/fa-solid.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:Font Awesome\ 5 Free;font-weight:900} -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | animation: fa-spin 2s infinite linear; 6 | } 7 | 8 | .@{fa-css-prefix}-pulse { 9 | animation: fa-spin 1s infinite steps(8); 10 | } 11 | 12 | @keyframes fa-spin { 13 | 0% { 14 | transform: rotate(0deg); 15 | } 16 | 100% { 17 | transform: rotate(360deg); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | border-radius: .1em; 6 | border: solid .08em @fa-border-color; 7 | padding: .2em .25em .15em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix}, .fas, .far, .fal, .fab { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}, .fas, .far, .fal, .fab { 5 | -moz-osx-font-smoothing: grayscale; 6 | -webkit-font-smoothing: antialiased; 7 | display: inline-block; 8 | font-style: normal; 9 | font-variant: normal; 10 | text-rendering: auto; 11 | line-height: 1; 12 | } 13 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | text-align: center; 5 | width: (20em / 16); 6 | } 7 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | .larger(@factor) when (@factor > 0) { 5 | .larger((@factor - 1)); 6 | 7 | .@{fa-css-prefix}-@{factor}x { 8 | font-size: (@factor * 1em); 9 | } 10 | } 11 | 12 | /* makes the font 33% larger relative to the icon container */ 13 | .@{fa-css-prefix}-lg { 14 | font-size: (4em / 3); 15 | line-height: (3em / 4); 16 | vertical-align: -.0667em; 17 | } 18 | 19 | .@{fa-css-prefix}-xs { 20 | font-size: .75em; 21 | } 22 | 23 | .@{fa-css-prefix}-sm { 24 | font-size: .875em; 25 | } 26 | 27 | .larger(10); 28 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | list-style-type: none; 6 | margin-left: @fa-li-width * 5/4; 7 | padding-left: 0; 8 | 9 | > li { position: relative; } 10 | } 11 | 12 | .@{fa-css-prefix}-li { 13 | left: -@fa-li-width; 14 | position: absolute; 15 | text-align: center; 16 | width: @fa-li-width; 17 | line-height: inherit; 18 | } 19 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | -moz-osx-font-smoothing: grayscale; 6 | -webkit-font-smoothing: antialiased; 7 | display: inline-block; 8 | font-style: normal; 9 | font-variant: normal; 10 | font-weight: normal; 11 | line-height: 1; 12 | vertical-align: -.125em; 13 | } 14 | 15 | .fa-icon-rotate(@degrees, @rotation) { 16 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; 17 | transform: rotate(@degrees); 18 | } 19 | 20 | .fa-icon-flip(@horiz, @vert, @rotation) { 21 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; 22 | transform: scale(@horiz, @vert); 23 | } 24 | 25 | 26 | // Only display content to screen readers. A la Bootstrap 4. 27 | // 28 | // See: http://a11yproject.com/posts/how-to-hide-content/ 29 | 30 | .sr-only() { 31 | border: 0; 32 | clip: rect(0,0,0,0); 33 | height: 1px; 34 | margin: -1px; 35 | overflow: hidden; 36 | padding: 0; 37 | position: absolute; 38 | width: 1px; 39 | } 40 | 41 | // Use in conjunction with .sr-only to only display content when it's focused. 42 | // 43 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 44 | // 45 | // Credit: HTML5 Boilerplate 46 | 47 | .sr-only-focusable() { 48 | &:active, 49 | &:focus { 50 | clip: auto; 51 | height: auto; 52 | margin: 0; 53 | overflow: visible; 54 | position: static; 55 | width: auto; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | .@{fa-css-prefix}-flip-horizontal.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(-1, -1, 2); } 11 | 12 | // Hook for IE8-9 13 | // ------------------------- 14 | 15 | :root { 16 | .@{fa-css-prefix}-rotate-90, 17 | .@{fa-css-prefix}-rotate-180, 18 | .@{fa-css-prefix}-rotate-270, 19 | .@{fa-css-prefix}-flip-horizontal, 20 | .@{fa-css-prefix}-flip-vertical { 21 | filter: none; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/_stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | display: inline-block; 6 | height: 2em; 7 | line-height: 2em; 8 | position: relative; 9 | vertical-align: middle; 10 | width: 2em; 11 | } 12 | 13 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 14 | left: 0; 15 | position: absolute; 16 | text-align: center; 17 | width: 100%; 18 | } 19 | 20 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 21 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 22 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 23 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/fa-brands.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @import "_variables.less"; 6 | 7 | @font-face { 8 | font-family: 'Font Awesome 5 Brands'; 9 | font-style: normal; 10 | font-weight: normal; 11 | src: url('@{fa-font-path}/fa-brands-400.eot'); 12 | src: url('@{fa-font-path}/fa-brands-400.eot?#iefix') format('embedded-opentype'), 13 | url('@{fa-font-path}/fa-brands-400.woff2') format('woff2'), 14 | url('@{fa-font-path}/fa-brands-400.woff') format('woff'), 15 | url('@{fa-font-path}/fa-brands-400.ttf') format('truetype'), 16 | url('@{fa-font-path}/fa-brands-400.svg#fontawesome') format('svg'); 17 | } 18 | 19 | .fab { 20 | font-family: 'Font Awesome 5 Brands'; 21 | } 22 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/fa-regular.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @import "_variables.less"; 6 | 7 | @font-face { 8 | font-family: 'Font Awesome 5 Free'; 9 | font-style: normal; 10 | font-weight: 400; 11 | src: url('@{fa-font-path}/fa-regular-400.eot'); 12 | src: url('@{fa-font-path}/fa-regular-400.eot?#iefix') format('embedded-opentype'), 13 | url('@{fa-font-path}/fa-regular-400.woff2') format('woff2'), 14 | url('@{fa-font-path}/fa-regular-400.woff') format('woff'), 15 | url('@{fa-font-path}/fa-regular-400.ttf') format('truetype'), 16 | url('@{fa-font-path}/fa-regular-400.svg#fontawesome') format('svg'); 17 | } 18 | 19 | .far { 20 | font-family: 'Font Awesome 5 Free'; 21 | font-weight: 400; 22 | } 23 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/fa-solid.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @import "_variables.less"; 6 | 7 | @font-face { 8 | font-family: 'Font Awesome 5 Free'; 9 | font-style: normal; 10 | font-weight: 900; 11 | src: url('@{fa-font-path}/fa-solid-900.eot'); 12 | src: url('@{fa-font-path}/fa-solid-900.eot?#iefix') format('embedded-opentype'), 13 | url('@{fa-font-path}/fa-solid-900.woff2') format('woff2'), 14 | url('@{fa-font-path}/fa-solid-900.woff') format('woff'), 15 | url('@{fa-font-path}/fa-solid-900.ttf') format('truetype'), 16 | url('@{fa-font-path}/fa-solid-900.svg#fontawesome') format('svg'); 17 | } 18 | 19 | .fa, 20 | .fas { 21 | font-family: 'Font Awesome 5 Free'; 22 | font-weight: 900; 23 | } 24 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/less/fontawesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @import "_variables.less"; 6 | @import "_mixins.less"; 7 | @import "_core.less"; 8 | @import "_larger.less"; 9 | @import "_fixed-width.less"; 10 | @import "_list.less"; 11 | @import "_bordered-pulled.less"; 12 | @import "_animated.less"; 13 | @import "_rotated-flipped.less"; 14 | @import "_stacked.less"; 15 | @import "_icons.less"; 16 | @import "_screen-reader.less"; 17 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | animation: fa-spin 2s infinite linear; 6 | } 7 | 8 | .#{$fa-css-prefix}-pulse { 9 | animation: fa-spin 1s infinite steps(8); 10 | } 11 | 12 | @keyframes fa-spin { 13 | 0% { 14 | transform: rotate(0deg); 15 | } 16 | 17 | 100% { 18 | transform: rotate(360deg); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | border: solid .08em $fa-border-color; 6 | border-radius: .1em; 7 | padding: .2em .25em .15em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix}, 14 | .fas, 15 | .far, 16 | .fal, 17 | .fab { 18 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 19 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 20 | } 21 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}, 5 | .fas, 6 | .far, 7 | .fal, 8 | .fab { 9 | -moz-osx-font-smoothing: grayscale; 10 | -webkit-font-smoothing: antialiased; 11 | display: inline-block; 12 | font-style: normal; 13 | font-variant: normal; 14 | text-rendering: auto; 15 | line-height: 1; 16 | } 17 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | text-align: center; 5 | width: (20em / 16); 6 | } 7 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | // makes the font 33% larger relative to the icon container 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -.0667em; 9 | } 10 | 11 | .#{$fa-css-prefix}-xs { 12 | font-size: .75em; 13 | } 14 | 15 | .#{$fa-css-prefix}-sm { 16 | font-size: .875em; 17 | } 18 | 19 | @for $i from 1 through 10 { 20 | .#{$fa-css-prefix}-#{$i}x { 21 | font-size: $i * 1em; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | list-style-type: none; 6 | margin-left: $fa-li-width * 5/4; 7 | padding-left: 0; 8 | 9 | > li { position: relative; } 10 | } 11 | 12 | .#{$fa-css-prefix}-li { 13 | left: -$fa-li-width; 14 | position: absolute; 15 | text-align: center; 16 | width: $fa-li-width; 17 | line-height: inherit; 18 | } 19 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon { 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | display: inline-block; 8 | font-style: normal; 9 | font-variant: normal; 10 | font-weight: normal; 11 | line-height: 1; 12 | vertical-align: -.125em; 13 | } 14 | 15 | @mixin fa-icon-rotate($degrees, $rotation) { 16 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 17 | transform: rotate($degrees); 18 | } 19 | 20 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 21 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 22 | transform: scale($horiz, $vert); 23 | } 24 | 25 | 26 | // Only display content to screen readers. A la Bootstrap 4. 27 | // 28 | // See: http://a11yproject.com/posts/how-to-hide-content/ 29 | 30 | @mixin sr-only { 31 | border: 0; 32 | clip: rect(0, 0, 0, 0); 33 | height: 1px; 34 | margin: -1px; 35 | overflow: hidden; 36 | padding: 0; 37 | position: absolute; 38 | width: 1px; 39 | } 40 | 41 | // Use in conjunction with .sr-only to only display content when it's focused. 42 | // 43 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 44 | // 45 | // Credit: HTML5 Boilerplate 46 | 47 | @mixin sr-only-focusable { 48 | &:active, 49 | &:focus { 50 | clip: auto; 51 | height: auto; 52 | margin: 0; 53 | overflow: visible; 54 | position: static; 55 | width: auto; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | .#{$fa-css-prefix}-flip-horizontal.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(-1, -1, 2); } 11 | 12 | // Hook for IE8-9 13 | // ------------------------- 14 | 15 | :root { 16 | .#{$fa-css-prefix}-rotate-90, 17 | .#{$fa-css-prefix}-rotate-180, 18 | .#{$fa-css-prefix}-rotate-270, 19 | .#{$fa-css-prefix}-flip-horizontal, 20 | .#{$fa-css-prefix}-flip-vertical { 21 | filter: none; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only; } 5 | .sr-only-focusable { @include sr-only-focusable; } 6 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | display: inline-block; 6 | height: 2em; 7 | line-height: 2em; 8 | position: relative; 9 | vertical-align: middle; 10 | width: 2em; 11 | } 12 | 13 | .#{$fa-css-prefix}-stack-1x, 14 | .#{$fa-css-prefix}-stack-2x { 15 | left: 0; 16 | position: absolute; 17 | text-align: center; 18 | width: 100%; 19 | } 20 | 21 | .#{$fa-css-prefix}-stack-1x { 22 | line-height: inherit; 23 | } 24 | 25 | .#{$fa-css-prefix}-stack-2x { 26 | font-size: 2em; 27 | } 28 | 29 | .#{$fa-css-prefix}-inverse { 30 | color: $fa-inverse; 31 | } 32 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/fa-brands.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @import 'variables'; 6 | 7 | @font-face { 8 | font-family: 'Font Awesome 5 Brands'; 9 | font-style: normal; 10 | font-weight: normal; 11 | src: url('#{$fa-font-path}/fa-brands-400.eot'); 12 | src: url('#{$fa-font-path}/fa-brands-400.eot?#iefix') format('embedded-opentype'), 13 | url('#{$fa-font-path}/fa-brands-400.woff2') format('woff2'), 14 | url('#{$fa-font-path}/fa-brands-400.woff') format('woff'), 15 | url('#{$fa-font-path}/fa-brands-400.ttf') format('truetype'), 16 | url('#{$fa-font-path}/fa-brands-400.svg#fontawesome') format('svg'); 17 | } 18 | 19 | .fab { 20 | font-family: 'Font Awesome 5 Brands'; 21 | } 22 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/fa-regular.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @import 'variables'; 6 | 7 | @font-face { 8 | font-family: 'Font Awesome 5 Free'; 9 | font-style: normal; 10 | font-weight: 400; 11 | src: url('#{$fa-font-path}/fa-regular-400.eot'); 12 | src: url('#{$fa-font-path}/fa-regular-400.eot?#iefix') format('embedded-opentype'), 13 | url('#{$fa-font-path}/fa-regular-400.woff2') format('woff2'), 14 | url('#{$fa-font-path}/fa-regular-400.woff') format('woff'), 15 | url('#{$fa-font-path}/fa-regular-400.ttf') format('truetype'), 16 | url('#{$fa-font-path}/fa-regular-400.svg#fontawesome') format('svg'); 17 | } 18 | 19 | .far { 20 | font-family: 'Font Awesome 5 Free'; 21 | font-weight: 400; 22 | } 23 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/fa-solid.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @import 'variables'; 6 | 7 | @font-face { 8 | font-family: 'Font Awesome 5 Free'; 9 | font-style: normal; 10 | font-weight: 900; 11 | src: url('#{$fa-font-path}/fa-solid-900.eot'); 12 | src: url('#{$fa-font-path}/fa-solid-900.eot?#iefix') format('embedded-opentype'), 13 | url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'), 14 | url('#{$fa-font-path}/fa-solid-900.woff') format('woff'), 15 | url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype'), 16 | url('#{$fa-font-path}/fa-solid-900.svg#fontawesome') format('svg'); 17 | } 18 | 19 | .fa, 20 | .fas { 21 | font-family: 'Font Awesome 5 Free'; 22 | font-weight: 900; 23 | } 24 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/scss/fontawesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.0.9 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @import 'variables'; 6 | @import 'mixins'; 7 | @import 'core'; 8 | @import 'larger'; 9 | @import 'fixed-width'; 10 | @import 'list'; 11 | @import 'bordered-pulled'; 12 | @import 'animated'; 13 | @import 'rotated-flipped'; 14 | @import 'stacked'; 15 | @import 'icons'; 16 | @import 'screen-reader'; 17 | -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /resources/assets/css/icons/font-awesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/font-awesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /resources/assets/css/icons/simple-line-icons/fonts/Simple-Line-Icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/simple-line-icons/fonts/Simple-Line-Icons.eot -------------------------------------------------------------------------------- /resources/assets/css/icons/simple-line-icons/fonts/Simple-Line-Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/simple-line-icons/fonts/Simple-Line-Icons.ttf -------------------------------------------------------------------------------- /resources/assets/css/icons/simple-line-icons/fonts/Simple-Line-Icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/simple-line-icons/fonts/Simple-Line-Icons.woff -------------------------------------------------------------------------------- /resources/assets/css/icons/simple-line-icons/fonts/Simple-Line-Icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/simple-line-icons/fonts/Simple-Line-Icons.woff2 -------------------------------------------------------------------------------- /resources/assets/css/icons/themify-icons/fonts/themify.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/themify-icons/fonts/themify.eot -------------------------------------------------------------------------------- /resources/assets/css/icons/themify-icons/fonts/themify.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/themify-icons/fonts/themify.ttf -------------------------------------------------------------------------------- /resources/assets/css/icons/themify-icons/fonts/themify.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reziamini/laravel-easypanel/de90ec62dc88cac4e962642074fa503cc178d127/resources/assets/css/icons/themify-icons/fonts/themify.woff -------------------------------------------------------------------------------- /resources/assets/css/rtl.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: "Vazir"; 3 | } 4 | 5 | .sidebar-nav .has-arrow::after { 6 | left: 15px; 7 | right: unset; 8 | } 9 | 10 | .sidebar-nav .base-level-line { 11 | border-right: 1px solid rgba(0, 0, 0, .1); 12 | margin-right: 40px; 13 | border-left: 0; 14 | margin-left: 0; 15 | } 16 | 17 | .sidebar-nav #sidebarnav .sidebar-item .sidebar-link { 18 | margin-left: 17px; 19 | margin-right: 0; 20 | } 21 | 22 | .sidebar-nav #sidebarnav .sidebar-item .first-level .sidebar-item.active .sidebar-link::before { 23 | left: unset; 24 | right: 0; 25 | } 26 | 27 | .sidebar-nav #sidebarnav .sidebar-item.selected > .sidebar-link { 28 | border-radius: 60px 0 0 60px; 29 | } 30 | 31 | .container-fluid { 32 | text-align: right; 33 | } 34 | 35 | .form-control.is-invalid, .was-validated .form-control:invalid { 36 | background-position: center left calc(.375em + .1875rem); 37 | padding-left: calc(1.5em + .75rem); 38 | } 39 | 40 | .dropdown-item { 41 | text-align: right; 42 | } 43 | 44 | .card-title { 45 | text-align: right; 46 | } 47 | 48 | .topbar .user-dd { 49 | min-width: unset; 50 | } 51 | 52 | .sidebar-link .hide-menu { 53 | margin-right: 0.5rem; 54 | } 55 | 56 | .notification { 57 | left: 0; 58 | } 59 | 60 | .form-check-label { 61 | margin-right: 1.3rem; 62 | } 63 | 64 | .custom-checkbox + p { 65 | margin-right: 10px; 66 | } 67 | 68 | .breadcrumb-item + .breadcrumb-item { 69 | padding: 0 !important; 70 | } 71 | 72 | .breadcrumb-item + .breadcrumb-item:before { 73 | padding-left: .5rem !important; 74 | } 75 | 76 | .left-sidebar, .topbar, .topbar .top-navbar .navbar-nav > .nav-item { 77 | transition: right .2s ease-in; 78 | } 79 | 80 | @media (min-width: 768px) { 81 | #main-wrapper[data-layout=vertical][data-sidebar-position=fixed][data-sidebartype=full] .topbar .top-navbar .navbar-collapse { 82 | margin-right: 260px; 83 | margin-left: 0; 84 | } 85 | 86 | #main-wrapper[data-layout=vertical][data-sidebartype=full] .page-wrapper { 87 | margin-left: 0; 88 | margin-right: 260px; 89 | } 90 | 91 | #main-wrapper[data-layout=vertical][data-sidebar-position=fixed][data-sidebartype=mini-sidebar] .topbar .top-navbar .navbar-collapse, 92 | #main-wrapper[data-layout=vertical][data-sidebartype=mini-sidebar] .page-wrapper { 93 | margin-left: 0; 94 | margin-right: 65px; 95 | } 96 | } 97 | 98 | @media (max-width: 767.98px) { 99 | #main-wrapper.show-sidebar .left-sidebar { 100 | right: 0 !important; 101 | } 102 | #main-wrapper[data-sidebartype="mini-sidebar"] .left-sidebar { 103 | left: 0; 104 | right: -260px; 105 | } 106 | .container-checkbox { 107 | margin-left: 0; 108 | margin-right: 15px; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /resources/assets/js/app-style-switcher.min.js: -------------------------------------------------------------------------------- 1 | $(function(){"use strict";$(".theme-color .theme-item .theme-link").on("click",function(){var a=$(this).attr("data-logobg");$(".topbar .top-navbar .navbar-header").attr("data-logobg",a)}),"skin6"==$("#main-wrapper").attr("data-navbarbg")&&($(".topbar .navbar").addClass("navbar-light"),$(".topbar .navbar").removeClass("navbar-dark")),$(".theme-color .theme-item .theme-link").on("click",function(){var a=$(this).attr("data-navbarbg");$("#main-wrapper").attr("data-navbarbg",a),$(".topbar .navbar-collapse").attr("data-navbarbg",a),"skin6"==$("#main-wrapper").attr("data-navbarbg")?($(".topbar .navbar").addClass("navbar-light"),$(".topbar .navbar").removeClass("navbar-dark")):($(".topbar .navbar").removeClass("navbar-light"),$(".topbar .navbar").addClass("navbar-dark"))}),$(".theme-color .theme-item .theme-link").on("click",function(){var a=$(this).attr("data-sidebarbg");$(".left-sidebar").attr("data-sidebarbg",a),$(".scroll-sidebar").attr("data-sidebarbg",a)}),$("#sidebar-position").change(function(){$(this).is(":checked")?($("#main-wrapper").attr("data-sidebar-position","fixed"),$(".topbar .top-navbar .navbar-header").attr("data-navheader","fixed")):($("#main-wrapper").attr("data-sidebar-position","absolute"),$(".topbar .top-navbar .navbar-header").attr("data-navheader","relative"))}),$("#header-position").change(function(){$(this).is(":checked")?$("#main-wrapper").attr("data-header-position","fixed"):$("#main-wrapper").attr("data-header-position","relative")}),$("#boxed-layout").change(function(){$(this).is(":checked")?$("#main-wrapper").attr("data-boxed-layout","boxed"):$("#main-wrapper").attr("data-boxed-layout","full")}),$("#theme-view").change(function(){$(this).is(":checked")?$("body").attr("data-theme","dark"):$("body").attr("data-theme","light")});function a(){(0li >a.has-arrow").on("click",function(s){s.preventDefault()})}); -------------------------------------------------------------------------------- /resources/lang/en_panel.json: -------------------------------------------------------------------------------- 1 | { 2 | "Hello": "Hello", 3 | "EasyPanel": "EasyPanel", 4 | "Logout": "Logout", 5 | "CRUD Menu": "CRUD Menu", 6 | "Applications": "Applications", 7 | "Home": "Home", 8 | "Create": "Create", 9 | "Cancel": "Cancel", 10 | "Congrats": "Congrats", 11 | "ListTitle": ":Name List", 12 | "Yes, Delete it": "Yes, Delete it", 13 | "No, Cancel it": "No, Cancel it", 14 | "DeleteMessage": "Do You really want to delete this :name ?", 15 | "DeleteTitle": "Delete a :Name", 16 | "DeletedMessage": ":Name was deleted.", 17 | "CreatedMessage": ":Name was created.", 18 | "UpdatedMessage": ":Name was updated.", 19 | "CannotUpdateMessage": ":Name can't be updated.", 20 | "CannotDeleteMessage": ":Name can't be deleted.", 21 | "CreateTitle": "Create :Name", 22 | "UpdateTitle": "Update :Name", 23 | "Search": "Search", 24 | "Action": "Action", 25 | "Update": "Update", 26 | "Dashboard": "Dashboard", 27 | "List": "List", 28 | "BuildTitle" : "Build a CRUD", 29 | "BuildMessage": "Do You really want to build this CRUD ? (Components will be replaced)", 30 | "Yes, Build it": "Yes, Build it.", 31 | "CRUD was activated": "CRUD was activated", 32 | "CRUD was inactivated": "CRUD was inactivated", 33 | "CRUD Created successfully": "CRUD Created successfully", 34 | "Model namespace": "Model namespace", 35 | "UnknownError": "Something went wrong!", 36 | "CRUD": "CRUD", 37 | "Route is invalid": "Route is invalid", 38 | "Namespace is invalid": "Namespace is invalid", 39 | "Model": "Model", 40 | "Route": "Route", 41 | "Status": "Status", 42 | "Built": "Built", 43 | "CRUD's Route": "CRUD's Route", 44 | "Your CRUD list": "Your CRUD list", 45 | "CRUD Manager": "CRUD Manager", 46 | "There is no record for CRUD in database!": "There is no record for CRUD in database!", 47 | "Re-Build All": "Re-Build All", 48 | "More icons in": "More icons in", 49 | "FontAwesome": "FontAwesome", 50 | "Name of custom language": "Name of custom language", 51 | "Translation": "Translation", 52 | "Role": "Role", 53 | "Role Manager": "Role Manager", 54 | "Name Of Role": "Name Of Role", 55 | "With ACL": "With ACL", 56 | "With Policy": "With Policy", 57 | "Needs to be protected using roles and permissions.": "Needs to be protected using roles and permissions.", 58 | "Admin can only delete its own data in table.": "Admin can only delete its own data in table.", 59 | "There is no record for Role in database!": "There is no record for Role in database!", 60 | "Users Count": "Users Count", 61 | "Admin": "Admin", 62 | "Admins": "Admins", 63 | "Admin Manager": "Admin Manager", 64 | "Select Roles": "Select Roles", 65 | "Without Role": "Without Role", 66 | "name": "Name", 67 | "email": "Email", 68 | "Full Access": "Full Access", 69 | "Lists": "Lists", 70 | "Delete": "Delete" 71 | } 72 | -------------------------------------------------------------------------------- /resources/lang/fa_panel.json: -------------------------------------------------------------------------------- 1 | { 2 | "Hello": "سلام", 3 | "EasyPanel": "پنل مدیریت", 4 | "Logout": "خروج", 5 | "CRUD Menu": "منوی کراد", 6 | "Applications": "برنامه", 7 | "Home": "خانه", 8 | "Create": "ساخت", 9 | "Cancel": "لغو", 10 | "Congrats": "تبریک", 11 | "ListTitle": "لیست :Name", 12 | "Yes, Delete it.": "آره، حذفش کن.", 13 | "No, Cancel it.": "نه لغوش کن.", 14 | "DeleteMessage": "آیا واقعا میخواید این :name رو حذف کنید ?", 15 | "DeleteTitle": "حذف یک :Name", 16 | "DeletedMessage": ":Name حذف شد.", 17 | "CreatedMessage": ":Name ساخته شد.", 18 | "UpdatedMessage": ":Name ویرایش شد.", 19 | "CannotUpdateMessage": ":Name مجاز به ویرایش نیست", 20 | "CannotDeleteMessage": ":Name مجاز به حذف نیست.", 21 | "CreateTitle": "ساخت :Name", 22 | "UpdateTitle": "ویرایش :Name", 23 | "Search": "جستجو", 24 | "Action": "عملیات", 25 | "Update": "ویرایش", 26 | "Dashboard": "داشبورد", 27 | "List": "لیست", 28 | "BuildTitle" : "ساخت کراد", 29 | "BuildMessage": "آیا واقعا میخواهید کراد را مجددا بسازید ؟ (تمامی کامپوننت ها از اول ساخته میشوند)", 30 | "Yes, Build it": "آره، بساز", 31 | "CRUD was activated": "کراد فعال شد.", 32 | "CRUD was inactivated": "کراد غیرفعال شد.", 33 | "CRUD Created successfully": "کراد با موفقیت ساخته شد", 34 | "Model namespace": "نیم اسپیس مدل", 35 | "UnknownError": "خطایی رخ داده!", 36 | "CRUD": "کراد", 37 | "Crud": "کراد", 38 | "lists": "لیست", 39 | "read": "نمایش", 40 | "create": "ایجاد", 41 | "update": "ویرایش", 42 | "delete": "حذف", 43 | "Route is invalid": "روت اشتباه است!", 44 | "Namespace is invalid": "نیم اسپیس اشتباه است!", 45 | "Model": "مدل", 46 | "Route": "روت", 47 | "Status": "وضعیت", 48 | "Built": "ساخته شده", 49 | "CRUD's Route": "روت کراد", 50 | "Your CRUD list": "لیست کراد های شما", 51 | "CRUD Manager": "مدیریت کراد", 52 | "There is no record for CRUD in database!": "کرادی در دیتابیسی ثبت نشده!", 53 | "Re-Build All": "ساخت همه", 54 | "FontAwesome": "فونت آوسم", 55 | "More icons in": "آیکون های بیشتر در", 56 | "Name of custom language": "نام زبان مورد نظر", 57 | "Translation": "ترجمه", 58 | "Role": "نقش", 59 | "Role Manager": "مدیریت نقش‌ها", 60 | "Name Of Role": "نام نقش", 61 | "With ACL": "دارای سطوح دسترسی", 62 | "With Policy": "چک کردن دسترسی‌ها", 63 | "Needs to be protected using roles and permissions.": "در صورت فعال بودن، سطوح دسترسی بررسی میشود.", 64 | "Admin can only delete its own data in table.": "کاربر فقط اطلاعات ساخته شده توسط خود را میتواند مدیریت کند.", 65 | "There is no record for Role in database!": "هیچ نقشی در دیتابیس پیدا نشد!", 66 | "Users Count": "تعداد کاربران", 67 | "Admin": "مدیر", 68 | "Admins": "مدیران", 69 | "Admin Manager": "مدیریت مدیران", 70 | "Select Roles": "انتخاب نقش‌ها", 71 | "Without Role": "بدون نقش", 72 | "name": "نام", 73 | "email": "ایمیل", 74 | "Full Access": "دسترسی کامل", 75 | "Lists": "لیست", 76 | "Delete": "حذف" 77 | } 78 | -------------------------------------------------------------------------------- /resources/views/components/crud-menu-item.blade.php: -------------------------------------------------------------------------------- 1 | @if (hasPermission(getRouteName().".{$crud->route}.*", $crud->with_acl)) 2 | 26 | @endif 27 | -------------------------------------------------------------------------------- /resources/views/home.blade.php: -------------------------------------------------------------------------------- 1 | @component('admin::layouts.app') 2 |

You can edit & customize this page in resources/views/vendor/admin/home.blade.php

3 | 4 |

Features :

5 | 17 | 18 |

Check document out : Github repo

19 | @endcomponent 20 | -------------------------------------------------------------------------------- /resources/views/layouts/child-sidebar-menu.blade.php: -------------------------------------------------------------------------------- 1 |
  • 2 | 3 | @foreach(\EasyPanel\Models\CRUD::active() as $crud) 4 | 5 | @endforeach 6 | -------------------------------------------------------------------------------- /resources/views/layouts/sidebar.blade.php: -------------------------------------------------------------------------------- 1 | 69 | -------------------------------------------------------------------------------- /resources/views/livewire/admins/create.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    {{ __('CreateTitle', ['name' => __('Role') ]) }}

    4 |
    5 | 10 |
    11 |
    12 | 13 |
    14 | 15 |
    16 |
    17 | 18 |
    19 |
    20 | 21 | @error('name')
    {{ $message }}
    @enderror 22 |
    23 |
    24 |
    25 | 26 |
    27 | @foreach($permissions as $key => $value) 28 |
    29 |
    30 |
    31 |

    {{ str_replace('.', ' => ', $key) }}

    32 | @php 33 | $dashKey = str_replace('.', '-', $key); 34 | @endphp 35 | @foreach($value as $keyAccess) 36 |
    37 | 38 | 39 |
    40 | @endforeach 41 |
    42 |
    43 |
    44 | @endforeach 45 |
    46 |
    47 | 48 | 52 |
    53 | 54 |
    55 | -------------------------------------------------------------------------------- /resources/views/livewire/admins/lists.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    {{ __('ListTitle', ['name' => __('Admins')]) }}

    6 | {{--{{ __('CreateTitle', ['name' => __('Admins') ]) }}--}} 7 |
    8 | 9 | 13 |
    14 | 15 |
    16 | @if($admins->count() > 0) 17 |
    18 | 19 | 20 | 21 | @php $firstAdmin = $admins->first(); @endphp 22 | @foreach($firstAdmin->getFillable() as $fillable) 23 | @if( ! in_array($fillable, $firstAdmin->getHidden())) @endif 24 | @endforeach 25 | 26 | 27 | 28 | @foreach($admins as $admin) 29 | @livewire('admin::livewire.admins.single', ['admin' => $admin], key($admin->id)) 30 | @endforeach 31 | 32 |
    {{ __($fillable) }}{{ __('Action') }}
    33 |
    34 | @else 35 |
    36 | {{ __('There is no record for Admins in database!') }} 37 |
    38 | @endif 39 | 40 |
    41 | 42 |
    43 |
    44 | -------------------------------------------------------------------------------- /resources/views/livewire/admins/single.blade.php: -------------------------------------------------------------------------------- 1 | 2 | {{ $admin->name }} 3 | {{ $admin->email }} 4 | 5 | 6 | @if(hasPermission(getRouteName().'.admins.update', true)) 7 | 8 | 9 | 10 | @endif 11 | 12 | @if(hasPermission(getRouteName().'.admins.delete', true) && auth()->id() !== $admin->id) 13 | 16 | 17 |
    18 |
    19 |
    {{ __('DeleteTitle', ['name' => __('Admin') ]) }}
    20 |

    {{ __('DeleteMessage', ['name' => __('Admin') ]) }}

    21 | 25 |
    26 |
    27 | @endif 28 | 29 | -------------------------------------------------------------------------------- /resources/views/livewire/admins/update.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    {{ __('UpdateTitle', ['name' => __('Admins') ]) }}

    4 |
    5 | 10 |
    11 |
    12 | 13 |
    14 | 15 |
    16 |
    {{__('Select Roles')}}
    17 |
    18 |
    19 |
    20 | 21 | 27 | 28 | @error('selectedRoles')
    {{ $message }}
    @enderror 29 |
    30 |
    31 | 32 | {{--
    33 |
    34 | 35 | @error('route')
    {{ $message }}
    @enderror 36 |
    37 |
    38 | 39 |
    40 |
    41 | 42 | 43 | @error('icon')
    {{ $message }}
    @enderror 44 |

    {{ __('More icons in') }} {{ __('FontAwesome') }}

    45 |
    46 |
    --}} 47 |
    48 |
    49 | 50 | 54 |
    55 | 56 |
    57 | -------------------------------------------------------------------------------- /resources/views/livewire/crud/create.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    {{ __('CreateTitle', ['name' => __('CRUD') ]) }}

    4 |
    5 | 10 |
    11 |
    12 | 13 |
    14 | 15 |
    16 |
    17 |
    18 |
    19 | 20 | @if($models and $dropdown) 21 |
    22 | @foreach($models as $key => $model) 23 |
    24 | {{ $model }} 25 |
    26 | @endforeach 27 |
    28 | @endif 29 | @error('model')
    {{ $message }}
    @enderror 30 |
    31 |
    32 | 33 |
    34 |
    35 | 36 | @error('route')
    {{ $message }}
    @enderror 37 |
    38 |
    39 | 40 |
    41 |
    42 | 43 | 44 | @error('icon')
    {{ $message }}
    @enderror 45 |

    {{ __('More icons in') }} {{ __('FontAwesome') }}

    46 |
    47 |
    48 | 49 |
    50 |
    51 | 52 | 53 |
    54 | {{ __('Needs to be protected using roles and permissions.') }} 55 | 56 |
    57 |
    58 |
    59 | 60 | 61 |
    62 | {{ __('Admin can only delete its own data in table.') }} 63 |
    64 |
    65 |
    66 | 67 | 71 |
    72 | 73 |
    74 | -------------------------------------------------------------------------------- /resources/views/livewire/crud/lists.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    {{ __('ListTitle', ['name' => __('CRUD')]) }}

    6 | {{ __('CreateTitle', ['name' => __('CRUD') ]) }} 7 |
    8 | 9 | 13 |
    14 | 15 | 16 |
    17 | @if($cruds->count() > 0) 18 |
    19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | @foreach($cruds as $crud) 32 | @livewire('admin::livewire.crud.single', ['crud' => $crud], key($crud->id)) 33 | @endforeach 34 | 35 |
    {{ __('Model') }}{{ __('Route') }}{{ __('Status') }}{{ __('With ACL') }}{{ __('With Policy') }}{{ __('Built') }}{{ __('Action') }}
    36 |
    37 | @if(hasPermission(getRouteName().'.crud.create', true)) 38 | {{ __('Re-Build All') }} 39 |
    40 |
    41 |
    {{ __('BuildTitle') }}
    42 |

    {{ __('BuildMessage') }}

    43 | 47 |
    48 |
    49 | @endif 50 | @else 51 |
    52 | {{ __('There is no record for CRUD in database!') }} 53 |
    54 | @endif 55 | 56 |
    57 | 58 |
    59 |
    60 | -------------------------------------------------------------------------------- /resources/views/livewire/crud/single.blade.php: -------------------------------------------------------------------------------- 1 | 2 | {{ $crud->model }}::class 3 | /{{ $crud->route }} 4 | @if($crud->active) Active @else Inactive @endif 5 | @if($crud->with_acl) Yes @else No @endif 6 | @if($crud->with_policy) Yes @else No @endif 7 | @if($crud->built) Yes @else No @endif 8 | 9 | @if(hasPermission(getRouteName().'.crud.delete', true)) 10 | 13 | 14 |
    15 |
    16 |
    {{ __('DeleteTitle', ['name' => __('CRUD') ]) }}
    17 |

    {{ __('DeleteMessage', ['name' => __('CRUD') ]) }}

    18 | 22 |
    23 |
    24 | @endif 25 | 26 | @if(hasPermission(getRouteName().'.crud.create', true)) 27 | 30 | 31 |
    32 |
    33 |
    {{ __('BuildTitle') }}
    34 |

    {{ __('BuildMessage') }}

    35 | 39 |
    40 |
    41 | @endif 42 | 43 | @if(hasPermission(getRouteName().'.crud.create', true)) 44 | @if($crud->active) 45 | 48 | @else 49 | 52 | @endif 53 | @endif 54 | 55 | 56 | -------------------------------------------------------------------------------- /resources/views/livewire/role/create.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    {{ __('CreateTitle', ['name' => __('Role') ]) }}

    4 |
    5 | 10 |
    11 |
    12 | 13 |
    14 | 15 |
    16 |
    17 | 18 |
    19 |
    20 | 21 | @error('name')
    {{ __($message) }}
    @enderror 22 |
    23 |
    24 | 25 |
    26 |
    27 |
    28 | 32 | 33 | 34 |
    35 |
    36 |
    37 |
    38 | 39 |
    40 | @foreach($permissions as $key => $value) 41 | @php 42 | $hasAdminDotPrefix = strpos($key, 'admin.') !== false; 43 | 44 | $dashKey = str_replace('.', '-', $key); 45 | $entityName = $hasAdminDotPrefix ? ucfirst(str_replace('admin.', '', $key)) : ucfirst($key); 46 | 47 | if($hasAdminDotPrefix) 48 | $value = array_merge($value, [['name'=>'delete']]); 49 | @endphp 50 |
    51 |
    52 | 53 |
    54 | 55 |
    56 | 57 |
    58 |

    {{ __($entityName) }}

    59 |
    60 | 61 |
    62 | 64 |
    65 | 66 |
    67 |
    68 | 69 | 70 |
    71 | 72 |
    73 | @foreach($value as $keyAccess) 74 |
    75 | 76 |
    77 | 79 |
    80 | 81 |
    82 | 87 |
    88 | 89 |
    90 | @endforeach 91 |
    92 | 93 |
    94 |
    95 | 96 | @endforeach 97 |
    98 |
    99 | 100 | 104 |
    105 | 106 |
    107 | 108 | 119 | 120 | 121 | 131 | -------------------------------------------------------------------------------- /resources/views/livewire/role/lists.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    {{ __('ListTitle', ['name' => __('Role')]) }}

    6 | 7 | @if(hasPermission(getRouteName().'.role.delete', true)) 8 | {{ __('CreateTitle', ['name' => __('Role') ]) }} 9 | @endif 10 |
    11 | 12 | 16 |
    17 | 18 |
    19 | @if($roles->count() > 0) 20 |
    21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | @foreach($roles as $role) 30 | @livewire('admin::livewire.role.single', ['role' => $role], key($role->id)) 31 | @endforeach 32 | 33 |
    {{ __('name') }}{{ __('Users Count') }}{{ __('Action') }}
    34 |
    35 | @else 36 |
    37 | {{ __('There is no record for Role in database!') }} 38 |
    39 | @endif 40 | 41 |
    42 | 43 |
    44 |
    45 | -------------------------------------------------------------------------------- /resources/views/livewire/role/single.blade.php: -------------------------------------------------------------------------------- 1 | 2 | {{ $role->name }} 3 | {{ $role->users()->count() }} 4 | 5 | 6 | @if(hasPermission(getRouteName().'.role.update', true) && !$role->is_super_admin()) 7 | 8 | 9 | 10 | @endif 11 | 12 | @if(hasPermission(getRouteName().'.role.delete', true) && !$role->is_super_admin()) 13 | 16 | 17 |
    18 |
    19 |
    {{ __('DeleteTitle', ['name' => __('Role') ]) }}
    20 |

    {{ __('DeleteMessage', ['name' => __('Role') ]) }}

    21 | 25 |
    26 |
    27 | @endif 28 | 29 | -------------------------------------------------------------------------------- /resources/views/livewire/role/update.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    {{ __('UpdateTitle', ['name' => __('Role') ]) }}

    4 |
    5 | 10 |
    11 |
    12 | 13 |
    14 | 15 |
    16 |
    17 | 18 |
    19 |
    20 | 21 | @error('name')
    {{ __($message) }}
    @enderror 22 |
    23 |
    24 | 25 |
    26 |
    27 |
    28 | 33 | 34 | 35 |
    36 |
    37 |
    38 |
    39 | 40 |
    41 | @foreach($permissions as $key => $value) 42 | @php 43 | $hasAdminDotPrefix = strpos($key, 'admin.') !== false; 44 | 45 | $dashKey = str_replace('.', '-', $key); 46 | $entityName = $hasAdminDotPrefix ? ucfirst(str_replace('admin.', '', $key)) : ucfirst($key); 47 | 48 | if($hasAdminDotPrefix) 49 | $value = array_merge($value, [['name'=>'delete']]); 50 | @endphp 51 |
    52 |
    53 | 54 |
    55 | 56 |
    57 | 58 |
    59 |

    {{ __($entityName) }}

    60 |
    61 | 62 |
    63 | 64 |
    65 | 66 |
    67 |
    68 | 69 | 70 |
    71 | 72 |
    73 | @foreach($value as $keyAccess) 74 | @php $check = isset($access[$dashKey][$keyAccess['name']]); @endphp 75 |
    76 | 77 |
    78 | 79 |
    80 | 81 |
    82 | 89 |
    90 | 91 |
    92 | @endforeach 93 |
    94 | 95 |
    96 |
    97 | 98 | @endforeach 99 |
    100 |
    101 | 102 | 106 |
    107 | 108 |
    109 | 110 | 121 | 122 | -------------------------------------------------------------------------------- /resources/views/livewire/translation/manage.blade.php: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    {{ __('Translation') }}

    6 |
    7 | 12 |
    13 |
    14 | 15 | 19 |
    20 | 21 | 22 |
    23 | 24 |
    25 |
    26 |
    27 |
    28 | 29 | @error('language')
    {{ $message }}
    @enderror 30 |
    31 |
    32 |
    33 |
    34 | 35 |
    36 |
    37 | @foreach($texts as $key => $text) 38 |
    39 |
    40 | 41 |
    42 |
    43 |
    44 |
    45 | 46 |
    47 |
    48 | @endforeach 49 |
    50 |
    51 | 52 | 56 |
    57 |
    58 |
    59 | -------------------------------------------------------------------------------- /src/Commands/Actions/DeleteCRUD.php: -------------------------------------------------------------------------------- 1 | argument('name') ?: CRUD::query()->where('active', true)->pluck('name')->toArray(); 19 | 20 | if($names == null) { 21 | throw new CommandNotFoundException("There is no action in database"); 22 | } 23 | 24 | foreach ($names as $name) { 25 | if (!in_array($name, CRUD::query()->pluck('name')->toArray())) { 26 | $this->line("$name does not exist in config file"); 27 | continue; 28 | } 29 | 30 | if ($this->askResult($name)) { 31 | File::deleteDirectory(resource_path("/views/livewire/admin/$name")); 32 | File::deleteDirectory(app_path("/Http/Livewire/Admin/" . ucfirst($name))); 33 | File::delete(app_path("/CRUD/".ucfirst($name)."Component.php")); 34 | $this->info("{$name} files were deleted, make sure you will delete {$name} value from actions in config"); 35 | CRUD::query()->where('name', $name)->delete(); 36 | } else { 37 | $this->line("process for {$name} action was canceled."); 38 | } 39 | 40 | } 41 | } 42 | 43 | public function askResult($name) 44 | { 45 | if($this->option('force')) { 46 | return true; 47 | } 48 | $result = $this->confirm("Do you really want to delete {$name} files ?", true); 49 | return $result; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/Commands/Actions/Install.php: -------------------------------------------------------------------------------- 1 | warn("\nInstalling Admin panel ..."); 19 | 20 | Artisan::call('vendor:publish', [ 21 | '--provider' => EasyPanelServiceProvider::class, 22 | '--tag' => 'easy-panel-styles' 23 | ]); 24 | 25 | Artisan::call('vendor:publish', [ 26 | '--provider' => EasyPanelServiceProvider::class, 27 | '--tag' => 'easy-panel-views' 28 | ]); 29 | 30 | Artisan::call('vendor:publish', [ 31 | '--provider' => EasyPanelServiceProvider::class, 32 | '--tag' => 'easy-panel-config' 33 | ]); 34 | 35 | Artisan::call('vendor:publish', [ 36 | '--provider' => EasyPanelServiceProvider::class, 37 | '--tag' => 'easy-panel-cruds' 38 | ]); 39 | 40 | Artisan::call('vendor:publish', [ 41 | '--provider' => EasyPanelServiceProvider::class, 42 | '--tag' => 'easy-panel-lang' 43 | ]); 44 | 45 | Artisan::call('vendor:publish', [ 46 | '--provider' => EasyPanelServiceProvider::class, 47 | '--tag' => 'easy-panel-migration' 48 | ]); 49 | 50 | Artisan::call('vendor:publish', [ 51 | '--provider' => DynamicAclServiceProvider::class 52 | ]); 53 | 54 | Artisan::call('migrate'); 55 | 56 | $this->line("\nEasy panel was installed 🎉\n\nBuild an amazing admin panel less than 5 minutes 🤓\n"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Commands/Actions/MakeCRUD.php: -------------------------------------------------------------------------------- 1 | argument('name') ? 18 | [$this->argument('name')] : 19 | CRUD::query()->where('active', true)->pluck('name')->toArray(); 20 | 21 | if(is_null($names)) { 22 | throw new CommandNotFoundException("There is no action in config file"); 23 | } 24 | 25 | foreach ($names as $name) { 26 | $args = ['name' => $name, '--force' => $this->option('force')]; 27 | $instance = getCrudConfig($name); 28 | 29 | $this->createActions($instance, $name, $args); 30 | } 31 | } 32 | 33 | private function createActions($instance, $name, $args) 34 | { 35 | if (isset($instance->create) and $instance->create) { 36 | $this->call('panel:create', $args); 37 | } else { 38 | $this->warn("The create action is disabled for {$name}"); 39 | } 40 | 41 | if (isset($instance->update) and $instance->update) { 42 | $this->call('panel:update', $args); 43 | } else { 44 | $this->warn("The update action is disabled for {$name}"); 45 | } 46 | 47 | $this->call('panel:read', $args); 48 | $this->call('panel:single', $args); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/Commands/Actions/MakeCRUDConfig.php: -------------------------------------------------------------------------------- 1 | resolveStubPath('crud.stub'); 19 | } 20 | 21 | public function handle() 22 | { 23 | $name = $this->getNameInput(); 24 | 25 | $path = base_path("app/CRUD/{$name}Component.php"); 26 | 27 | if($this->files->exists($path) and !$this->option('force')){ 28 | $this->warn("'{$name}Component.php' already exists in CRUD directory"); 29 | return; 30 | } 31 | 32 | $this->makeDirectory($path); 33 | 34 | $stub = $this->files->get($this->getStub()); 35 | $newStub = $this->parseStub($stub); 36 | 37 | $this->files->put($path, $newStub); 38 | $this->info("{$name} config file was created for {$this->getNameInput()} model\nYou can manage it in : app/CRUD/{$name}Component.php"); 39 | } 40 | 41 | private function parseStub($stub) 42 | { 43 | $array = [ 44 | '{{ modelNamespace }}' => $this->parseModel(), 45 | '{{ modelName }}' => $this->getNameInput(), 46 | '{{ withAuth }}' => $this->withAuth(), 47 | '{{ fields }}' => $this->parseSearchFields(), 48 | ]; 49 | 50 | return str_replace(array_keys($array), array_values($array), $stub); 51 | } 52 | 53 | protected function getOptions() 54 | { 55 | return [ 56 | ['force', 'f', InputOption::VALUE_NONE, 'force mode'], 57 | ]; 58 | } 59 | 60 | private function parseModel() 61 | { 62 | $model = $this->qualifyModel($this->getNameInput()); 63 | 64 | if(!class_exists($model)){ 65 | $this->warn("Model option should be valid and model should be exist"); 66 | die(); 67 | } 68 | 69 | return $model; 70 | } 71 | 72 | private function withAuth() 73 | { 74 | $fillableList = $this->getFillableList(); 75 | if(!in_array('user_id', $fillableList)){ 76 | return 'true'; 77 | } 78 | 79 | return 'false'; 80 | } 81 | 82 | private function getFillableList() 83 | { 84 | $modelNamespace = $this->qualifyModel($this->getNameInput()); 85 | $modelInstance = new $modelNamespace; 86 | return $modelInstance->getFillable(); 87 | } 88 | 89 | private function parseSearchFields() 90 | { 91 | $fillableList = $this->getFillableList(); 92 | $array = []; 93 | foreach ($fillableList as $fillable){ 94 | if(!Str::contains($fillable, 'id')){ 95 | $array[] = "'$fillable'"; 96 | } 97 | } 98 | 99 | return implode(', ', $array); 100 | } 101 | 102 | private function resolveStubPath($stub) 103 | { 104 | return file_exists($customPath = base_path(trim("stubs/panel/".$stub, '/'))) 105 | ? $customPath 106 | : __DIR__.'/../stub/'.$stub; 107 | } 108 | 109 | protected function qualifyModel($model) 110 | { 111 | $model = ltrim($model, '\\/'); 112 | 113 | $model = str_replace('/', '\\', $model); 114 | 115 | $rootNamespace = $this->rootNamespace(); 116 | 117 | if (Str::startsWith($model, $rootNamespace)) { 118 | return $model; 119 | } 120 | 121 | return is_dir(app_path('Models')) 122 | ? $rootNamespace.'Models\\'.$model 123 | : $rootNamespace.$model; 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/Commands/Actions/Migration.php: -------------------------------------------------------------------------------- 1 | EasyPanelServiceProvider::class, 19 | '--tag' => 'easy-panel-migrations' 20 | ]); 21 | 22 | $this->line("\nMigrations were published"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Commands/Actions/PublishStubs.php: -------------------------------------------------------------------------------- 1 | EasyPanelServiceProvider::class, 19 | '--tag' => 'easy-panel-stubs' 20 | ]); 21 | 22 | $this->info("Stubs was published successfully"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Commands/Actions/Reinstall.php: -------------------------------------------------------------------------------- 1 | confirm("Do you really want to reinstall the panel ? (All components will be deleted)", true); 17 | 18 | if(!$status) { 19 | $this->info("The process was canceled"); 20 | return; 21 | } 22 | 23 | Artisan::call("panel:uninstall", [ 24 | '--force' => true, 25 | ]); 26 | 27 | Artisan::call("panel:install"); 28 | 29 | $this->info("The package was reinstalled!"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Commands/Actions/Uninstall.php: -------------------------------------------------------------------------------- 1 | option('force') ? true : $this->confirm("Do you really want to uninstall the panel ? (All files and components will be deleted)", true); 20 | 21 | if (!$status) { 22 | $this->info("The process was canceled"); 23 | return; 24 | } 25 | 26 | // Delete folders and files which EasyPanel published 27 | $this->deleteFiles(); 28 | 29 | // Drop tables which has been created by EasyPanel 30 | $this->dropTables(); 31 | 32 | $this->deleteMigrations(); 33 | 34 | $this->info("All files and components was deleted!"); 35 | } 36 | 37 | private function dropTables() 38 | { 39 | Schema::dropIfExists('cruds'); 40 | Schema::dropIfExists('panel_admins'); 41 | Schema::dropIfExists('role_user'); 42 | Schema::dropIfExists('roles'); 43 | } 44 | 45 | private function deleteFiles() 46 | { 47 | File::deleteDirectory(app_path('Http/Livewire/Admin')); 48 | File::deleteDirectory(app_path('CRUD')); 49 | File::deleteDirectory(resource_path('views/livewire/admin')); 50 | File::deleteDirectory(resource_path('views/vendor/admin')); 51 | File::deleteDirectory(resource_path('cruds')); 52 | File::deleteDirectory(public_path('assets/admin')); 53 | File::delete(config_path('easy_panel.php')); 54 | File::delete(config_path('dynamicACL.php')); 55 | File::delete(LangManager::getFiles()); 56 | } 57 | 58 | private function deleteMigrations() 59 | { 60 | $migrationFiles = File::glob(database_path('migrations/*999999*.php')); 61 | 62 | File::delete($migrationFiles); 63 | 64 | DB::table('migrations') 65 | ->where('migration', 'like', '%999999%') 66 | ->delete(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Commands/CRUDActions/CommandBase.php: -------------------------------------------------------------------------------- 1 | getNameInput()); 29 | $this->path = parent::getDefaultNamespace($rootNamespace).DIRECTORY_SEPARATOR."Http".DIRECTORY_SEPARATOR."Livewire".DIRECTORY_SEPARATOR."Admin".DIRECTORY_SEPARATOR."$name"; 30 | 31 | return $this->path; 32 | } 33 | 34 | protected function buildClass($name) 35 | { 36 | $stub = parent::buildClass($name); 37 | $stub = $this->stubParser->replaceModel($stub); 38 | 39 | return $stub; 40 | } 41 | 42 | protected function getPath($name) 43 | { 44 | $fileName = ucfirst($this->file); 45 | return "{$this->path}".DIRECTORY_SEPARATOR."{$fileName}.php"; 46 | } 47 | 48 | protected function getStub() 49 | { 50 | return $this->resolveStubPath("{$this->file}.stub"); 51 | } 52 | 53 | private function buildBlade() 54 | { 55 | $stub = $this->files->get($this->resolveStubPath("blade".DIRECTORY_SEPARATOR."{$this->file}.blade.stub")); 56 | $newStub = $this->stubParser->parseBlade($stub); 57 | 58 | $directoryName = strtolower($this->getNameInput()); 59 | $path = $this->viewPath("livewire".DIRECTORY_SEPARATOR."admin".DIRECTORY_SEPARATOR."{$directoryName}".DIRECTORY_SEPARATOR."{$this->file}.blade.php"); 60 | 61 | $this->makeDirectory($path); 62 | 63 | $this->files->put($path, $newStub); 64 | } 65 | 66 | public function handle() 67 | { 68 | $this->setCRUDInstance(); 69 | $this->setStubParser(); 70 | 71 | if ($this->isReservedName($this->getNameInput())) { 72 | $this->error("The name '{$this->getNameInput()}' is reserved by PHP."); 73 | return false; 74 | } 75 | 76 | $name = $this->qualifyClass($this->getNameInput()); 77 | $path = $this->getPath($name); 78 | $path = str_replace('App', 'app', $path); 79 | 80 | if ($this->alreadyExists($this->getNameInput()) and !$this->option('force')) { 81 | $this->line(" • {$this->getNameInput()} {$this->type} already exists! \n"); 82 | 83 | return false; 84 | } 85 | 86 | $this->makeDirectory(base_path($path)); 87 | 88 | $component = $this->sortImports($this->buildClass($name)); 89 | $this->files->put(base_path($path), $component); 90 | 91 | $this->buildBlade(); 92 | $this->line(" {$this->getNameInput()} {$this->type} created successfully. 🤙\n"); 93 | } 94 | 95 | protected function getOptions() 96 | { 97 | return [ 98 | ['force', 'f', InputOption::VALUE_NONE, 'force mode'] 99 | ]; 100 | } 101 | 102 | private function setCRUDInstance(){ 103 | $modelName = $this->getNameInput(); 104 | 105 | return $this->crudInstance = getCrudConfig($modelName); 106 | } 107 | 108 | private function setStubParser() 109 | { 110 | $model = $this->crudInstance->getModel(); 111 | $parsedModel = $this->qualifyModel($model); 112 | $this->stubParser = new StubParser($this->getNameInput(), $parsedModel); 113 | $this->setDataToParser(); 114 | } 115 | 116 | private function resolveStubPath($stub) 117 | { 118 | return file_exists($customPath = base_path(trim("stubs/panel/".$stub, '/'))) 119 | ? $customPath 120 | : __DIR__.'/../stub/'.$stub; 121 | } 122 | 123 | protected function qualifyModel($model) 124 | { 125 | if (class_exists($model)){ 126 | return $model; 127 | } 128 | 129 | $model = ltrim($model, '\\/'); 130 | 131 | $model = str_replace('/', '\\', $model); 132 | 133 | $rootNamespace = $this->rootNamespace(); 134 | 135 | if (Str::startsWith($model, $rootNamespace)) { 136 | return $model; 137 | } 138 | 139 | return is_dir(app_path('Models')) 140 | ? $rootNamespace.'Models\\'.$model 141 | : $rootNamespace.$model; 142 | } 143 | 144 | private function setDataToParser() 145 | { 146 | $this->stubParser->setAuthType($this->crudInstance->with_user_id ?? false); 147 | $this->stubParser->setInputs($this->crudInstance->inputs()); 148 | $this->stubParser->setFields($this->crudInstance->fields()); 149 | $this->stubParser->setStore($this->crudInstance->storePaths()); 150 | $this->stubParser->setValidationRules($this->crudInstance->validationRules()); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/Commands/CRUDActions/MakeCreate.php: -------------------------------------------------------------------------------- 1 | argument('user'); 17 | 18 | if($this->askResult($user)){ 19 | UserProviderFacade::deleteAdmin($user); 20 | $this->info('Admin was removed successfully'); 21 | return; 22 | } 23 | 24 | $this->warn('Process was canceled'); 25 | } 26 | 27 | public function askResult($user) 28 | { 29 | if($this->option('force')) { 30 | return true; 31 | } 32 | 33 | return $this->confirm("Do you want to remove {$user} from administration", 'yes'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Commands/UserActions/GetAdmins.php: -------------------------------------------------------------------------------- 1 | warn('Admin Lists :'); 18 | foreach ($admins as $admin){ 19 | $message = $admin->panelAdmin->is_superuser 20 | ? "• {$admin->name}: {$admin->email} ( Super Admin ✅ )" 21 | : "• {$admin->name}: {$admin->email}"; 22 | 23 | $this->warn($message); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Commands/UserActions/MakeAdmin.php: -------------------------------------------------------------------------------- 1 | argument('user'); 18 | try{ 19 | $status = UserProviderFacade::makeAdmin($user, $this->option('super')); 20 | $method = $status['type'] == 'success' ? 'info' : 'warn'; 21 | 22 | $this->$method($status['message']); 23 | } catch (\Exception $exception){ 24 | $this->warn("Something went wrong!\nError: ". $exception->getMessage()); 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/Commands/stub/blade/create.blade.stub: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    {{ __('CreateTitle', ['name' => __('{{ modelName }}') ]) }}

    4 | 11 |
    12 | 13 |
    14 | 15 |
    16 | {{ inputs }} 17 |
    18 | 19 | 23 |
    24 |
    25 | -------------------------------------------------------------------------------- /src/Commands/stub/blade/read.blade.stub: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |

    {{ __('ListTitle', ['name' => __(\Illuminate\Support\Str::plural('{{ modelName }}')) ]) }}

    6 | 7 |
    8 | 9 | 13 | 14 |
    15 | @if(getCrudConfig('{{ modelName }}')->create && hasPermission(getRouteName().'.{{ routeName }}.create', {{ with_acl }}, {{ with_policy }})) 16 | 19 | @endif 20 | @if(getCrudConfig('{{ modelName }}')->searchable()) 21 |
    22 |
    23 | 24 |
    25 | 29 |
    30 |
    31 |
    32 | @endif 33 |
    34 |
    35 |
    36 | 37 |
    38 | 39 | 40 | 41 | {{ titles }} 42 | @if(getCrudConfig('{{ modelName }}')->delete or getCrudConfig('{{ modelName }}')->update) 43 | 44 | @endif 45 | 46 | 47 | 48 | @foreach(${{ model }}s as ${{ model }}) 49 | @livewire('admin.{{ model }}.single', [${{ model }}], key(${{ model }}->id)) 50 | @endforeach 51 | 52 |
    {{ __('Action') }}
    53 |
    54 |
    55 | {{ ${{ model }}s->appends(request()->query())->links() }} 56 |
    57 | 58 |
    59 | 60 |
    61 |
    62 |
    63 | -------------------------------------------------------------------------------- /src/Commands/stub/blade/single.blade.stub: -------------------------------------------------------------------------------- 1 | 2 | {{ data }} 3 | @if(getCrudConfig('{{ modelName }}')->delete or getCrudConfig('{{ modelName }}')->update) 4 | 5 | 6 | @if(getCrudConfig('{{ modelName }}')->update && hasPermission(getRouteName().'.{{ routeName }}.update', {{ with_acl }}, {{ with_policy }}, ${{ model }})) 7 | 8 | 9 | 10 | @endif 11 | 12 | @if(getCrudConfig('{{ modelName }}')->delete && hasPermission(getRouteName().'.{{ routeName }}.delete', {{ with_acl }}, {{ with_policy }}, ${{ model }})) 13 | 16 |
    17 |
    18 |
    {{ __('DeleteTitle', ['name' => __('{{ modelName }}') ]) }}
    19 |

    {{ __('DeleteMessage', ['name' => __('{{ modelName }}') ]) }}

    20 | 24 |
    25 |
    26 | @endif 27 | 28 | @endif 29 | 30 | -------------------------------------------------------------------------------- /src/Commands/stub/blade/update.blade.stub: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    {{ __('UpdateTitle', ['name' => __('{{ modelName }}') ]) }}

    4 | 11 |
    12 | 13 |
    14 | 15 |
    16 | 17 | {{ inputs }} 18 | 19 |
    20 | 21 | 25 |
    26 |
    27 | -------------------------------------------------------------------------------- /src/Commands/stub/create.stub: -------------------------------------------------------------------------------- 1 | validateOnly($input); 21 | } 22 | 23 | public function create() 24 | { 25 | if($this->getRules()) 26 | $this->validate(); 27 | 28 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('CreatedMessage', ['name' => __('{{ modelName }}') ])]); 29 | {{ uploadFile }} 30 | {{ modelName }}::create([ 31 | {{ fields }} 32 | ]); 33 | 34 | $this->reset(); 35 | } 36 | 37 | public function render() 38 | { 39 | return view('livewire.admin.{{ model }}.create') 40 | ->layout('admin::layouts.app', ['title' => __('CreateTitle', ['name' => __('{{ modelName }}') ])]); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Commands/stub/crud.stub: -------------------------------------------------------------------------------- 1 | sortType == 'desc' ? 'asc' : 'desc'; 32 | 33 | $this->sortColumn = $column; 34 | $this->sortType = $sort; 35 | } 36 | 37 | public function render() 38 | { 39 | $data = {{ modelName }}::query(); 40 | 41 | $instance = getCrudConfig('{{ model }}'); 42 | if($instance->searchable()){ 43 | $array = (array) $instance->searchable(); 44 | $data->where(function (Builder $query) use ($array){ 45 | foreach ($array as $item) { 46 | if(!\Str::contains($item, '.')) { 47 | $query->orWhere($item, 'like', '%' . $this->search . '%'); 48 | } else { 49 | $array = explode('.', $item); 50 | $query->orWhereHas($array[0], function (Builder $query) use ($array) { 51 | $query->where($array[1], 'like', '%' . $this->search . '%'); 52 | }); 53 | } 54 | } 55 | }); 56 | } 57 | 58 | if($this->sortColumn) { 59 | $data->orderBy($this->sortColumn, $this->sortType); 60 | } else { 61 | $data->latest('id'); 62 | } 63 | 64 | $data = $data->paginate(config('easy_panel.pagination_count', 15)); 65 | 66 | return view('livewire.admin.{{ model }}.read', [ 67 | '{{ model }}s' => $data 68 | ])->layout('admin::layouts.app', ['title' => __(\Str::plural('{{ modelName }}')) ]); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Commands/stub/single.stub: -------------------------------------------------------------------------------- 1 | {{ model }} = ${{ modelName }}; 15 | } 16 | 17 | public function delete() 18 | { 19 | $this->{{ model }}->delete(); 20 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => __('DeletedMessage', ['name' => __('{{ modelName }}') ]) ]); 21 | $this->emit('{{ model }}Deleted'); 22 | } 23 | 24 | public function render() 25 | { 26 | return view('livewire.admin.{{ model }}.single') 27 | ->layout('admin::layouts.app'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Commands/stub/update.stub: -------------------------------------------------------------------------------- 1 | {{ model }} = ${{ modelName }}; 22 | {{ setProperties }} 23 | } 24 | 25 | public function updated($input) 26 | { 27 | $this->validateOnly($input); 28 | } 29 | 30 | public function update() 31 | { 32 | if($this->getRules()) 33 | $this->validate(); 34 | 35 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('UpdatedMessage', ['name' => __('{{ modelName }}') ]) ]); 36 | {{ uploadFile }} 37 | $this->{{ model }}->update([ 38 | {{ fields }} 39 | ]); 40 | } 41 | 42 | public function render() 43 | { 44 | return view('livewire.admin.{{ model }}.update', [ 45 | '{{ model }}' => $this->{{ model }} 46 | ])->layout('admin::layouts.app', ['title' => __('UpdateTitle', ['name' => __('{{ modelName }}') ])]); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Concerns/Translatable.php: -------------------------------------------------------------------------------- 1 | texts)){ 14 | return; 15 | } 16 | 17 | $this->texts[$key ?? $text] = $text; 18 | } 19 | 20 | public function translate() 21 | { 22 | LangManager::updateAll($this->texts); 23 | } 24 | 25 | public function getTexts() 26 | { 27 | return $this->texts; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Contracts/CRUDComponent.php: -------------------------------------------------------------------------------- 1 | 'required|min:3|unique:roles', 17 | 'access' => 'required' 18 | ]; 19 | 20 | private function fixAccessKeys() 21 | { 22 | foreach($this->access as $key => $value) { 23 | unset($this->access[$key]); 24 | $key = str_replace('-', '.', $key); 25 | $this->access[$key] = $value; 26 | } 27 | 28 | return $this->access; 29 | } 30 | 31 | public function create() 32 | { 33 | $this->validate(); 34 | 35 | try { 36 | Role::create(['name' => $this->name, 'permissions' => $this->fixAccessKeys()]); 37 | 38 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('CreatedMessage', ['name' => __('Role') ])]); 39 | } catch (\Exception $exception){ 40 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => $exception->getMessage()]); 41 | } 42 | 43 | $this->reset(); 44 | } 45 | 46 | public function render() 47 | { 48 | $permissions = ACL::getRoutes(); 49 | 50 | return view('admin::livewire.role.create', compact('permissions')) 51 | ->layout('admin::layouts.app', ['title' => __('CreateTitle', ['name' => __('Role') ])]); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Http/Livewire/Admins/Lists.php: -------------------------------------------------------------------------------- 1 | layout('admin::layouts.app', ['title' => __('ListTitle', ['name' => __('Admins')])]); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Http/Livewire/Admins/Single.php: -------------------------------------------------------------------------------- 1 | admin = $admin; 16 | } 17 | 18 | public function delete() 19 | { 20 | if (auth()->id() == $this->admin->id) { 21 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => __('CannotDeleteMessage', ['name' => __('Admin')])]); 22 | return; 23 | } 24 | 25 | $this->admin->roles()->sync([]); 26 | 27 | UserProviderFacade::deleteAdmin($this->admin->id); 28 | 29 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => __('DeletedMessage', ['name' => __('Admin') ] )]); 30 | $this->emit('adminsUpdated'); 31 | } 32 | 33 | public function render() 34 | { 35 | return view('admin::livewire.admins.single') 36 | ->layout('admin::layouts.app'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Http/Livewire/Admins/Update.php: -------------------------------------------------------------------------------- 1 | 'required' 19 | ]; 20 | 21 | public function mount($admin) 22 | { 23 | $this->roles = Role::all(); 24 | 25 | $admin = UserProviderFacade::findUser($admin); 26 | 27 | $this->admin = $admin; 28 | 29 | $this->selectedRoles = $admin->roles()->pluck('id'); 30 | } 31 | 32 | public function updated($input) 33 | { 34 | $this->validateOnly($input); 35 | } 36 | 37 | public function update() 38 | { 39 | if ($this->getRules()) 40 | $this->validate(); 41 | 42 | if ($this->selectedRoles[0] == "null") 43 | $this->selectedRoles = []; 44 | 45 | $this->admin->roles()->sync($this->selectedRoles); 46 | 47 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('UpdatedMessage', ['name' => __('Admins')])]); 48 | } 49 | 50 | public function render() 51 | { 52 | return view('admin::livewire.admins.update', [ 53 | // pass roles here. 54 | ])->layout('admin::layouts.app', ['title' => __('UpdateTitle', ['name' => __('Admins')])]); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Http/Livewire/CRUD/Create.php: -------------------------------------------------------------------------------- 1 | 'required|min:8|unique:cruds', 21 | 'route' => 'required|min:2|unique:cruds', 22 | 'icon' => 'nullable|min:5', 23 | ]; 24 | 25 | public function closeModal() 26 | { 27 | $this->hideDropdown(); 28 | } 29 | 30 | public function setModel() 31 | { 32 | $this->models = $this->getModels(); 33 | $this->showDropdown(); 34 | } 35 | 36 | public function setSuggestedModel($key) 37 | { 38 | $this->model = $this->models[$key]; 39 | $this->route = Str::lower($this->getModelName($this->model)); 40 | $this->hideDropdown(); 41 | } 42 | 43 | public function updatedModel($value) 44 | { 45 | $value = $value == '' ? null : $value; 46 | $this->models = $this->getModels($value); 47 | $this->showDropdown(); 48 | } 49 | 50 | public function hideDropdown() 51 | { 52 | $this->dropdown = false; 53 | } 54 | 55 | public function showDropdown() 56 | { 57 | $this->dropdown = true; 58 | } 59 | 60 | public function create() 61 | { 62 | $this->validate(); 63 | 64 | if (!class_exists($this->model) or ! app()->make($this->model) instanceof Model){ 65 | $this->addError('model', __('Namespace is invalid')); 66 | 67 | return; 68 | } 69 | 70 | if (!preg_match('/^([a-z]|[0-9])+/', $this->route)){ 71 | $this->addError('route', __('Route is invalid')); 72 | 73 | return; 74 | } 75 | 76 | try{ 77 | $name = $this->getModelName($this->model); 78 | 79 | CRUD::create([ 80 | 'model' => trim($this->model, '\\'), 81 | 'name' => $name, 82 | 'route' => trim($this->route, '\\'), 83 | 'icon' => $this->icon ?? 'fas fa-bars', 84 | 'with_acl' => $this->withAcl == 1, 85 | 'with_policy' => $this->withAcl == 1 && $this->withPolicy == 1 86 | ]); 87 | 88 | Artisan::call('panel:config', [ 89 | 'name' => $name, 90 | '--force' => true 91 | ]); 92 | 93 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('CreatedMessage', ['name' => __('CRUD') ])]); 94 | } catch(\Exception $exception){ 95 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => __('UnknownError') ]); 96 | } 97 | 98 | 99 | $this->emit('crudUpdated'); 100 | $this->reset(); 101 | } 102 | 103 | public function render() 104 | { 105 | return view('admin::livewire.crud.create') 106 | ->layout('admin::layouts.app', ['title' => __('CreateTitle', ['name' => __('CRUD') ])]); 107 | } 108 | 109 | private function getModelName($model){ 110 | $model = explode('\\', $model); 111 | 112 | return end($model); 113 | } 114 | 115 | private function getModels($query = null) 116 | { 117 | $files = File::exists(app_path('/Models')) 118 | ? File::files(app_path('/Models')) 119 | : File::allFiles(app_path('/')); 120 | 121 | $array = []; 122 | 123 | foreach ($files as $file) { 124 | 125 | if ($this->fileCanNotBeListed($file->getFilename(), $query)){ 126 | continue; 127 | } 128 | 129 | $namespace = $this->fileNamespace($file->getFilename()); 130 | 131 | if (app()->make($namespace) instanceof Model) { 132 | $array[] = $namespace; 133 | } 134 | } 135 | 136 | return $array; 137 | } 138 | 139 | private function fileCanNotBeListed($fileName, $searchedValued = null): bool 140 | { 141 | return !Str::contains($fileName, '.php') or (!is_null($searchedValued) and !Str::contains(Str::lower($fileName), Str::lower($searchedValued))); 142 | } 143 | 144 | private function fileNamespace($fileName): string 145 | { 146 | $namespace = File::exists(app_path('/Models')) ? "App\\Models" : "\\App"; 147 | $fileName = str_replace('.php', null, $fileName); 148 | return $namespace."\\{$fileName}"; 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/Http/Livewire/CRUD/Lists.php: -------------------------------------------------------------------------------- 1 | true 27 | ]); 28 | 29 | CRUD::query()->where('active', true)->update([ 30 | 'built' => true 31 | ]); 32 | 33 | $this->dispatchBrowserEvent('show-message', [ 34 | 'type' => 'success', 35 | 'message' => __('CRUD Created successfully') 36 | ]); 37 | 38 | $this->redirect(route(getRouteName().'.crud.lists')); 39 | } 40 | 41 | public function render() 42 | { 43 | $cruds = CRUD::query() 44 | ->paginate(20); 45 | 46 | return view('admin::livewire.crud.lists', compact('cruds')) 47 | ->layout('admin::layouts.app', ['title' => __('ListTitle', ['name' => __('CRUD')])]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Http/Livewire/CRUD/Single.php: -------------------------------------------------------------------------------- 1 | crud = $crud; 17 | } 18 | 19 | public function delete() 20 | { 21 | Artisan::call('panel:delete', [ 22 | 'name' => $this->crud->name, 23 | '--force' => true, 24 | ]); 25 | 26 | $this->crud->delete(); 27 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => __('DeletedMessage', ['name' => __('CRUD') ] )]); 28 | $this->emit('crudUpdated'); 29 | } 30 | 31 | public function build() 32 | { 33 | Artisan::call('panel:crud', [ 34 | 'name' => $this->crud->name, 35 | '--force' => true, 36 | ]); 37 | 38 | $this->crud->update([ 39 | 'built' => true 40 | ]); 41 | 42 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('CRUD Created successfully') ] ); 43 | $this->emit('crudUpdated'); 44 | } 45 | 46 | public function inactive() 47 | { 48 | $this->crud->update([ 49 | 'active' => false 50 | ]); 51 | 52 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('CRUD was inactivated') ] ); 53 | $this->emit('crudUpdated'); 54 | } 55 | 56 | public function active() 57 | { 58 | $this->crud->update([ 59 | 'active' => true 60 | ]); 61 | 62 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('CRUD was activated') ] ); 63 | $this->emit('crudUpdated'); 64 | } 65 | 66 | public function render() 67 | { 68 | return view('admin::livewire.crud.single') 69 | ->layout('admin::layouts.app'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Http/Livewire/Role/Create.php: -------------------------------------------------------------------------------- 1 | 'required|min:3|unique:roles', 21 | 'access' => 'required' 22 | ]; 23 | 24 | private function fixAccessKeys() 25 | { 26 | foreach($this->access as $key => $value) { 27 | unset($this->access[$key]); 28 | $key = str_replace('-', '.', $key); 29 | $this->access[$key] = is_array($value) ? array_filter($value) : $value; 30 | } 31 | 32 | return array_filter($this->access); 33 | } 34 | 35 | /** 36 | * this method checks if whole checkboxes checked, set value true for SelectAll checkbox 37 | * 38 | * @param string $key 39 | * 40 | * @param string $dashKey 41 | */ 42 | public function checkSelectedAll($key, $dashKey) 43 | { 44 | $selectedRoutes = array_filter($this->access[$dashKey]); 45 | 46 | // we don't have delete route in cruds but we have a button for it. that's why i added 1 47 | $this->selectedAll[$dashKey] = count($selectedRoutes) == count($this->permissionsData[$key]) + 1; 48 | } 49 | 50 | public function create() 51 | { 52 | $this->validate(); 53 | 54 | try { 55 | Role::create(['name' => $this->name, 'permissions' => $this->fixAccessKeys()]); 56 | 57 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('CreatedMessage', ['name' => __('Role') ])]); 58 | } catch (\Exception $exception){ 59 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => $exception->getMessage()]); 60 | } 61 | 62 | $this->reset(); 63 | } 64 | 65 | public function render() 66 | { 67 | $this->permissionsData = ACL::getRoutes(); 68 | 69 | return view('admin::livewire.role.create', ['permissions' => $this->permissionsData]) 70 | ->layout('admin::layouts.app', ['title' => __('CreateTitle', ['name' => __('Role') ])]); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Http/Livewire/Role/Lists.php: -------------------------------------------------------------------------------- 1 | paginate(20); 26 | 27 | return view('admin::livewire.role.lists', compact('roles')) 28 | ->layout('admin::layouts.app', ['title' => __('ListTitle', ['name' => __('Roles')])]); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Http/Livewire/Role/Single.php: -------------------------------------------------------------------------------- 1 | role = $role; 16 | } 17 | 18 | public function delete() 19 | { 20 | if ($this->role->is_super_admin()) { 21 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => __('CannotDeleteMessage', ['name' => __('Role')])]); 22 | return; 23 | } 24 | 25 | $this->role->users()->sync([]); 26 | 27 | $this->role->delete(); 28 | 29 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => __('DeletedMessage', ['name' => __('Role') ] )]); 30 | $this->emit('roleUpdated'); 31 | } 32 | 33 | public function render() 34 | { 35 | return view('admin::livewire.role.single') 36 | ->layout('admin::layouts.app'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Http/Livewire/Role/Update.php: -------------------------------------------------------------------------------- 1 | 'min:3' 23 | ]; 24 | 25 | public function mount(Role $role) 26 | { 27 | $this->role = $role; 28 | 29 | $this->name = $role->name; 30 | 31 | $this->permissions = ACL::getRoutes(); 32 | 33 | $this->setSelectedAccess($role->permissions); 34 | } 35 | 36 | /** 37 | * this method checks if whole checkboxes checked, set value true for SelectAll checkbox 38 | * 39 | * @param string $key 40 | * 41 | * @param string $dashKey 42 | */ 43 | public function checkSelectedAll($key, $dashKey) 44 | { 45 | $selectedRoutes = array_filter($this->access[$dashKey]); 46 | 47 | // we don't have delete route in cruds but we have a button for it. that's why i added 1 48 | $this->selectedAll[$dashKey] = count($selectedRoutes) == count($this->permissions[$key]) + 1; 49 | } 50 | 51 | public function updated($input) 52 | { 53 | $this->validateOnly($input); 54 | } 55 | 56 | public function update() 57 | { 58 | if ($this->getRules()) 59 | $this->validate(); 60 | 61 | if ($this->role->is_super_admin()) { 62 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => __('CannotUpdateMessage', ['name' => __('Role')])]); 63 | return; 64 | } 65 | 66 | $this->role->update([ 67 | 'name' => $this->name, 68 | 'permissions' => $this->getSelectedAccess() 69 | ]); 70 | 71 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('UpdatedMessage', ['name' => __('Role')])]); 72 | } 73 | 74 | public function render() 75 | { 76 | return view('admin::livewire.role.update', [ 77 | 'role' => $this->role, 78 | ])->layout('admin::layouts.app', ['title' => __('UpdateTitle', ['name' => __('Role')])]); 79 | } 80 | 81 | private function setSelectedAccess($rolePermissions) 82 | { 83 | foreach($rolePermissions as $key => $value) { 84 | $dashKey = str_replace('.', '-', $key); 85 | $value = is_array($value) ? array_filter($value) : $value; 86 | 87 | if (empty($value)) 88 | continue; 89 | 90 | $this->access[$dashKey] = $value; 91 | 92 | $this->checkSelectedAll($key, $dashKey); 93 | } 94 | } 95 | 96 | private function getSelectedAccess() 97 | { 98 | $access = $this->access; 99 | 100 | foreach($access as $key => $value) { 101 | unset($access[$key]); 102 | $key = str_replace('-', '.', $key); 103 | $access[$key] = is_array($value) ? array_filter($value) : $value; 104 | } 105 | 106 | return $access; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Http/Livewire/Translation/Manage.php: -------------------------------------------------------------------------------- 1 | selectedLang = (config('easy_panel.lang') ?? 'en').'_panel'; 18 | $this->texts = LangManager::getTexts($this->selectedLang); 19 | } 20 | 21 | public function updatedSelectedLang($value) 22 | { 23 | $this->texts = LangManager::getTexts($value); 24 | } 25 | 26 | public function render() 27 | { 28 | return view('admin::livewire.translation.manage') 29 | ->layout('admin::layouts.app', ['title' => __('Translation')]); 30 | } 31 | 32 | protected function getRules() 33 | { 34 | return [ 35 | 'language' => 'required|min:2|max:10|string' 36 | ]; 37 | } 38 | 39 | public function create() 40 | { 41 | $this->validate(); 42 | try { 43 | $lang = strtolower($this->language) . '_panel'; 44 | File::copy(LangManager::getPath('en_panel'), LangManager::getPath($lang)); 45 | 46 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('CreatedMessage', ['name' => __('Translation') ])]); 47 | } catch (\Exception $exception){ 48 | $this->dispatchBrowserEvent('show-message', ['type' => 'error', 'message' => $exception->getMessage()]); 49 | } 50 | 51 | $this->reset('language'); 52 | } 53 | 54 | public function update() 55 | { 56 | LangManager::updateLanguage($this->selectedLang, $this->texts); 57 | 58 | $this->dispatchBrowserEvent('show-message', ['type' => 'success', 'message' => __('UpdatedMessage', ['name' => __('Translation') ])]); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Http/Middleware/LangChanger.php: -------------------------------------------------------------------------------- 1 | has('easypanel_lang') 15 | ? session()->get('easypanel_lang') 16 | : (config('easy_panel.lang') ?? 'en') .'_panel'; 17 | 18 | App::setLocale($lang); 19 | 20 | return $next($request); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/Http/Middleware/isAdmin.php: -------------------------------------------------------------------------------- 1 | shouldUse($defaultGuard); 17 | 18 | if(auth()->guest()){ 19 | return redirect($redirectPath); 20 | } 21 | 22 | if(!AuthFacade::check(auth()->user()->id)){ 23 | return redirect($redirectPath); 24 | } 25 | 26 | return $next($request); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/Models/CRUD.php: -------------------------------------------------------------------------------- 1 | setConnection(config('easy_panel.database.connection')); 22 | $this->setTable(config('easy_panel.database.crud_table')); 23 | 24 | parent::__construct($attributes); 25 | } 26 | 27 | public function scopeActive($query) 28 | { 29 | return $query->where('built', true)->where('active', true)->get(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Models/PanelAdmin.php: -------------------------------------------------------------------------------- 1 | setConnection(config('easy_panel.database.connection')); 23 | $this->setTable(config('easy_panel.database.panel_admin_table')); 24 | 25 | parent::__construct($attributes); 26 | } 27 | 28 | public function user() 29 | { 30 | return $this->belongsTo(config('easy_panel.user_model')); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Parsers/Fields/Field.php: -------------------------------------------------------------------------------- 1 | title = $title; 32 | $this->addText($title); 33 | } 34 | 35 | public static function title($title) 36 | { 37 | return new static($title); 38 | } 39 | 40 | public function style($style) 41 | { 42 | $this->style = $style; 43 | 44 | return $this; 45 | } 46 | 47 | public function asImage() 48 | { 49 | if($this->dataStub != 'linked-image.stub'){ 50 | $this->dataStub = 'image.stub'; 51 | } 52 | 53 | return $this; 54 | } 55 | 56 | public function clickableImage($target = '_blank') 57 | { 58 | $this->dataStub = 'linked-image.stub'; 59 | $this->target = $target; 60 | 61 | return $this; 62 | } 63 | 64 | public function asBadge() 65 | { 66 | $this->dataStub = 'badge.stub'; 67 | 68 | return $this; 69 | } 70 | 71 | public function asBooleanBadge($trueColor = 'success', $falseColor = 'danger') 72 | { 73 | $this->dataStub = 'bool-badge.stub'; 74 | $this->trueColor($trueColor); 75 | $this->falseColor($falseColor); 76 | 77 | return $this; 78 | } 79 | 80 | public function trueColor($color) 81 | { 82 | $this->trueColor = $color; 83 | 84 | return $this; 85 | } 86 | 87 | public function falseColor($color) 88 | { 89 | $this->falseColor = $color; 90 | 91 | return $this; 92 | } 93 | 94 | public function trueValue($value) 95 | { 96 | $this->trueValue = $value; 97 | $this->addText($value); 98 | 99 | return $this; 100 | } 101 | 102 | public function falseValue($value) 103 | { 104 | $this->falseValue = $value; 105 | $this->addText($value); 106 | 107 | return $this; 108 | } 109 | 110 | public function roundedImage() 111 | { 112 | $this->style .= " rounded-circle "; 113 | 114 | return $this; 115 | } 116 | 117 | public function alt($alt) 118 | { 119 | $this->alt = $alt; 120 | $this->addText($alt); 121 | 122 | return $this; 123 | } 124 | 125 | public function height($height) 126 | { 127 | $this->height = $height; 128 | 129 | return $this; 130 | } 131 | 132 | public function width($width) 133 | { 134 | $this->height = $width; 135 | 136 | return $this; 137 | } 138 | 139 | public function getTitle() 140 | { 141 | return $this->title; 142 | } 143 | 144 | public function badgeType($type) 145 | { 146 | $this->badgeType = $type; 147 | 148 | return $this; 149 | } 150 | 151 | public function roundedBadge() 152 | { 153 | $this->style .= ' badge-pill '; 154 | 155 | return $this; 156 | } 157 | 158 | public function setKey($key) 159 | { 160 | $this->key = $key; 161 | 162 | return $this; 163 | } 164 | 165 | public function setModel($model) 166 | { 167 | $this->model = $model; 168 | 169 | return $this; 170 | } 171 | 172 | public function renderTitle() 173 | { 174 | $stubContent = $this->getTitleStubContent(); 175 | 176 | $array = [ 177 | '{{ key }}' => $this->key, 178 | '{{ title }}' => $this->title 179 | ]; 180 | 181 | return str_replace(array_keys($array), array_values($array), $stubContent); 182 | } 183 | 184 | public function withoutSorting() 185 | { 186 | $this->headStub = 'not-sortable.stub'; 187 | 188 | return $this; 189 | } 190 | 191 | public function renderData() 192 | { 193 | $stubContent = $this->getDataStubContent(); 194 | 195 | $array = [ 196 | '{{ key }}' => $this->parseRelationalKey($this->key), 197 | '{{ model }}' => $this->model, 198 | '{{ height }}' => $this->height, 199 | '{{ width }}' => $this->width, 200 | '{{ style }}' => $this->style, 201 | '{{ alt }}' => $this->alt, 202 | '{{ badgeType }}' => $this->badgeType, 203 | '{{ target }}' => $this->target, 204 | '{{ trueColor }}' => $this->trueColor, 205 | '{{ trueValue }}' => $this->trueValue, 206 | '{{ falseColor }}' => $this->falseColor, 207 | '{{ falseValue }}' => $this->falseValue, 208 | ]; 209 | 210 | $this->translate(); 211 | 212 | return str_replace(array_keys($array), array_values($array), $stubContent); 213 | } 214 | 215 | private function getDataStubContent() 216 | { 217 | return file_get_contents(__DIR__.'/stubs/'.$this->dataStub); 218 | } 219 | 220 | private function getTitleStubContent() 221 | { 222 | if ($this->isRelational()){ 223 | return file_get_contents(__DIR__.'/stubs/titles/not-sortable.stub'); 224 | } 225 | 226 | return file_get_contents(__DIR__.'/stubs/titles/'.$this->headStub); 227 | } 228 | 229 | private function isRelational() 230 | { 231 | return \Str::contains($this->key, '.'); 232 | } 233 | 234 | private function parseRelationalKey($key){ 235 | return str_replace('.', '->', $key); 236 | } 237 | 238 | } 239 | -------------------------------------------------------------------------------- /src/Parsers/Fields/stubs/badge.stub: -------------------------------------------------------------------------------- 1 | {{ ${{ model }}->{{ key }} }} 2 | -------------------------------------------------------------------------------- /src/Parsers/Fields/stubs/bool-badge.stub: -------------------------------------------------------------------------------- 1 | {{ ${{ model }}->{{ key }} ? __('{{ trueValue }}') : __('{{ falseValue }}') }} 2 | -------------------------------------------------------------------------------- /src/Parsers/Fields/stubs/image.stub: -------------------------------------------------------------------------------- 1 | {{ alt }} 2 | -------------------------------------------------------------------------------- /src/Parsers/Fields/stubs/linked-image.stub: -------------------------------------------------------------------------------- 1 | {{ alt }} 2 | -------------------------------------------------------------------------------- /src/Parsers/Fields/stubs/text.stub: -------------------------------------------------------------------------------- 1 | {{ ${{ model }}->{{ key }} }} 2 | -------------------------------------------------------------------------------- /src/Parsers/Fields/stubs/titles/not-sortable.stub: -------------------------------------------------------------------------------- 1 | {{ __('{{ title }}') }} 2 | -------------------------------------------------------------------------------- /src/Parsers/Fields/stubs/titles/sortable.stub: -------------------------------------------------------------------------------- 1 | {{ __('{{ title }}') }} 2 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/BaseInput.php: -------------------------------------------------------------------------------- 1 | label = $label; 24 | $this->mode = config('easy_panel.lazy_mode') ? 'wire:model.lazy' : 'wire:model'; 25 | $this->addText($label); 26 | } 27 | 28 | public static function label($label) 29 | { 30 | return new static($label); 31 | } 32 | 33 | public function inputStyle($inputStyle) 34 | { 35 | $this->inputStyle = $inputStyle; 36 | 37 | return $this; 38 | } 39 | 40 | public function labelStyle($labelStyle) 41 | { 42 | $this->labelStyle = $labelStyle; 43 | 44 | return $this; 45 | } 46 | 47 | public function setKey($key) 48 | { 49 | $this->key = $key; 50 | 51 | return $this; 52 | } 53 | 54 | public function setAction($action) 55 | { 56 | $this->action = $action; 57 | 58 | return $this; 59 | } 60 | 61 | public function placeholder($placeholder) 62 | { 63 | $this->placeholder = $placeholder; 64 | $this->addText($placeholder); 65 | 66 | return $this; 67 | } 68 | 69 | public function lazyMode() 70 | { 71 | $this->mode = 'wire:model.lazy'; 72 | 73 | return $this; 74 | } 75 | 76 | public function normalMode() 77 | { 78 | $this->mode = 'wire:model'; 79 | 80 | return $this; 81 | } 82 | 83 | public function deferMode() 84 | { 85 | $this->mode = 'wire:model.defer'; 86 | 87 | return $this; 88 | } 89 | 90 | public function withoutAutocomplete() 91 | { 92 | $this->autocomplete = 'off'; 93 | 94 | return $this; 95 | } 96 | 97 | public function withoutAutofill() 98 | { 99 | $this->withoutAutocomplete(); 100 | 101 | return $this; 102 | } 103 | 104 | public function render() 105 | { 106 | $array = [ 107 | '{{ Title }}' => $this->label, 108 | '{{ Name }}' => $this->key, 109 | '{{ Mode }}' => $this->mode, 110 | '{{ Action }}' => $this->action, 111 | '{{ placeholder }}' => $this->placeholder, 112 | '{{ inputStyle }}' => $this->inputStyle, 113 | '{{ autocomplete }}' => $this->autocomplete, 114 | '{{ Provider }}' => $this->provider, 115 | '{{ labelStyle }}' => $this->labelStyle, 116 | ]; 117 | 118 | $this->translate(); 119 | 120 | return str_replace(array_keys($array), array_values($array), file_get_contents(__DIR__.'/stubs/'.$this->stub)); 121 | } 122 | 123 | public function getTitle() 124 | { 125 | return $this->label; 126 | } 127 | 128 | public function getPlaceholder() 129 | { 130 | return $this->placeholder; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/Checkbox.php: -------------------------------------------------------------------------------- 1 | Password::class, 11 | 'text' => Text::class, 12 | 'file' => File::class, 13 | 'email' => Email::class, 14 | 'number' => Number::class, 15 | 'textarea' => Textarea::class, 16 | 'select' => Select::class, 17 | 'ckeditor' => Ckeditor::class, 18 | 'checkbox' => Checkbox::class, 19 | 'date' => Date::class, 20 | 'datetime' => DateTime::class, 21 | 'time' => Time::class, 22 | ]; 23 | 24 | public static function get($name) 25 | { 26 | if (!key_exists($name, static::inputClassMap)){ 27 | throw new \Exception("The [$name] input type doesn't exist in input list!"); 28 | } 29 | 30 | return static::inputClassMap[$name]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/MultiSelect.php: -------------------------------------------------------------------------------- 1 | stub = 'multi-select-provider.stub'; 14 | 15 | [$class, $method] = $array; 16 | 17 | if (! class_exists($class)){ 18 | throw new Exception("Class {$class} doesn't exist."); 19 | } 20 | 21 | $method = $method ?: 'handle'; 22 | 23 | if (! method_exists($class, $method)){ 24 | throw new Exception("Method {$method} doesn't exist on {$class} class."); 25 | } 26 | 27 | $this->provider = "\\{$class}::{$method}()"; 28 | 29 | return $this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/Number.php: -------------------------------------------------------------------------------- 1 | stub = 'select-provider.stub'; 14 | 15 | [$class, $method] = $array; 16 | 17 | if (! class_exists($class)){ 18 | throw new Exception("Class {$class} doesn't exist."); 19 | } 20 | 21 | $method = $method ?: 'handle'; 22 | 23 | if (! method_exists($class, $method)){ 24 | throw new Exception("Method {$method} doesn't exist on {$class} class."); 25 | } 26 | 27 | $this->provider = "\\{$class}::{$method}()"; 28 | 29 | return $this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/Text.php: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
    4 | 5 | 6 |
    7 | @error('{{ Name }}')
    {{ $message }}
    @enderror 8 |
    9 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/ckeditor.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 |
    5 | 6 |
    7 | 20 | @error('{{ Name }}')
    {{ $message }}
    @enderror 21 |
    22 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/date.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @error('{{ Name }}')
    {{ $message }}
    @enderror 6 |
    7 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/datetime.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @error('{{ Name }}')
    {{ $message }}
    @enderror 6 |
    7 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/email.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @error('{{ Name }}')
    {{ $message }}
    @enderror 6 |
    7 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/file.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @if(${{ Name }} and !$errors->has('{{ Name }}') and ${{ Name }} instanceof Illuminate\Http\UploadedFile and ${{ Name }}->isPreviewable()) 6 | 7 | @endif 8 | @error('{{ Name }}')
    {{ $message }}
    @enderror 9 |
    10 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/multi-select-provider.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 9 | @error('{{ Name }}')
    {{ $message }}
    @enderror 10 |
    11 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/multi-select.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 9 | @error('{{ Name }}')
    {{ $message }}
    @enderror 10 |
    11 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/number.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @error('{{ Name }}')
    {{ $message }}
    @enderror 6 |
    7 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/password.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @error('{{ Name }}')
    {{ $message }}
    @enderror 6 |
    7 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/select-provider.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 9 | @error('{{ Name }}')
    {{ $message }}
    @enderror 10 |
    11 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/select.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 9 | @error('{{ Name }}')
    {{ $message }}
    @enderror 10 |
    11 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/text.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @error('{{ Name }}')
    {{ $message }}
    @enderror 6 |
    7 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/textarea.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @error('{{ Name }}')
    {{ $message }}
    @enderror 6 |
    7 | -------------------------------------------------------------------------------- /src/Parsers/HTMLInputs/stubs/time.stub: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | @error('{{ Name }}')
    {{ $message }}
    @enderror 6 |
    7 | -------------------------------------------------------------------------------- /src/Services/LangService.php: -------------------------------------------------------------------------------- 1 | mapWithKeys(function ($file, $key){ 15 | preg_match('/(\w+)_panel\.json/i', $file, $m); 16 | $key = "$m[1]_panel"; 17 | $value = Str::upper($m[1]); 18 | return [$key => $value]; 19 | })->toArray(); 20 | } 21 | 22 | public static function updateAll($texts) 23 | { 24 | foreach (static::getFiles() as $file) { 25 | $decodedFile = json_decode(File::get($file), 1); 26 | foreach ($texts as $key => $text) { 27 | if (array_key_exists($key, $decodedFile)){ 28 | unset($texts[$text]); 29 | } 30 | } 31 | $array = array_merge($decodedFile, $texts); 32 | File::put($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); 33 | } 34 | } 35 | 36 | public static function getFiles() 37 | { 38 | return File::glob(app()->langPath().DIRECTORY_SEPARATOR.'*_panel.json'); 39 | } 40 | 41 | public static function getTexts($lang) 42 | { 43 | return json_decode(static::getContent($lang), true); 44 | } 45 | 46 | public static function updateLanguage($lang, $texts) 47 | { 48 | $file = static::getContent($lang); 49 | 50 | $decodedFile = json_decode($file, 1); 51 | 52 | $array = array_merge($decodedFile, $texts); 53 | 54 | File::put(static::getPath($lang), json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); 55 | } 56 | 57 | public static function getContent($lang) 58 | { 59 | return File::get(static::getPath($lang)); 60 | } 61 | 62 | public static function getPath($lang) 63 | { 64 | return app()->langPath().DIRECTORY_SEPARATOR."{$lang}.json"; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Support/Auth/AdminIdentifier.php: -------------------------------------------------------------------------------- 1 | panelAdmin()->exists(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/Support/Contract/AuthFacade.php: -------------------------------------------------------------------------------- 1 | singleton(static::getFacadeAccessor(), $class); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Support/Contract/LangManager.php: -------------------------------------------------------------------------------- 1 | findUser($id); 14 | 15 | if ($user->panelAdmin()->exists()){ 16 | return [ 17 | 'type' => 'error', 18 | 'message' => 'User already is an admin!' 19 | ]; 20 | } 21 | 22 | $user->panelAdmin()->create([ 23 | 'is_superuser' => $is_super, 24 | ]); 25 | 26 | if($is_super) 27 | $this->makeSuperAdminRole($user); 28 | 29 | return [ 30 | 'type' => 'success', 31 | 'message' => "User '$id' was converted to an admin", 32 | ]; 33 | } 34 | 35 | public function getAdmins() 36 | { 37 | return $this->getUserModel()::query()->whereHas('panelAdmin')->with('panelAdmin')->get(); 38 | } 39 | 40 | public function paginateAdmins($perPage = 20) 41 | { 42 | return $this->getUserModel()::query()->whereHas('panelAdmin')->with('panelAdmin')->paginate($perPage); 43 | } 44 | 45 | public function findUser($id) 46 | { 47 | return $this->getUserModel()::query()->findOrFail($id); 48 | } 49 | 50 | public function deleteAdmin($id) 51 | { 52 | $user = $this->findUser($id); 53 | 54 | $user->panelAdmin()->delete(); 55 | } 56 | 57 | private function getUserModel() 58 | { 59 | return config('easy_panel.user_model') ?? User::class; 60 | } 61 | 62 | private function makeSuperAdminRole($user) 63 | { 64 | $role = Role::firstOrCreate(['name' => 'super_admin'], [ 65 | 'name' => 'super_admin', 66 | 'permissions' => [ 67 | 'fullAccess' => 1 68 | ] 69 | ]); 70 | 71 | $role->users()->sync([$user->id]); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/ViewComponents/CrudMenuItem.php: -------------------------------------------------------------------------------- 1 | crud = $crud; 16 | } 17 | 18 | public function render() 19 | { 20 | return view('admin::components.crud-menu-item'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/helpers.php: -------------------------------------------------------------------------------- 1 | make($namespace); 27 | 28 | if (!$instance instanceof CRUDComponent){ 29 | abort(403, "{$namespace} should implement CRUDComponent interface"); 30 | } 31 | 32 | return $instance; 33 | } 34 | } 35 | 36 | if(! function_exists('crud')) { 37 | function crud($name){ 38 | return \EasyPanel\Models\CRUD::query()->where('name', $name)->first(); 39 | } 40 | } 41 | 42 | if (! function_exists('hasPermission')) { 43 | function hasPermission($routeName, $withAcl, $withPolicy = false, $entity = []) { 44 | $showButton = true; 45 | 46 | if ($withAcl) { 47 | if (!auth()->user()->hasPermission($routeName)) { 48 | $showButton = false; 49 | } else if ($withPolicy && !auth()->user()->hasPermission($routeName, $entity)) { 50 | $showButton = false; 51 | } 52 | } 53 | 54 | return $showButton; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/routes.php: -------------------------------------------------------------------------------- 1 | name('home'); 12 | 13 | Route::post('/logout', function () { 14 | auth()->logout(); 15 | return redirect(config('easy_panel.redirect_unauthorized')); 16 | })->name('logout'); 17 | 18 | if (Schema::connection(config('easy_panel.database.connection'))->hasTable(config('easy_panel.database.crud_table'))) { 19 | foreach (CRUD::active() as $crud) { 20 | $crudConfig = getCrudConfig($crud->name); 21 | $name = ucfirst($crud->name); 22 | $component = "App\\Http\\Livewire\\Admin\\$name"; 23 | 24 | $middleware = []; 25 | if ($crud->with_acl) { 26 | $middleware[] = "dynamicAcl"; 27 | 28 | if ($crud->with_policy) 29 | $middleware[] = "authorize"; 30 | } 31 | 32 | Route::prefix($crud->route)->middleware($middleware)->name("{$crud->route}.")->group(function () use ($component, $crud, $crudConfig) { 33 | 34 | if (@class_exists("$component\\Read")) { 35 | Route::get('/', "$component\\Read")->name('read'); 36 | } 37 | 38 | if (@$crudConfig->create and @class_exists("$component\\Create")) { 39 | Route::get('/create', "$component\\Create")->name('create'); 40 | } 41 | 42 | if (@$crudConfig->update and @class_exists("$component\\Update")) { 43 | Route::get('/update/{' . $crud->name . '}', "$component\\Update")->name('update'); 44 | } 45 | 46 | }); 47 | } 48 | } 49 | 50 | Route::prefix('crud')->middleware('dynamicAcl')->name('crud.')->group(function () { 51 | Route::get('/', \EasyPanel\Http\Livewire\CRUD\Lists::class)->name('lists'); 52 | Route::get('/create', \EasyPanel\Http\Livewire\CRUD\Create::class)->name('create'); 53 | }); 54 | 55 | Route::get('setLang', function () { 56 | $lang = request()->get('lang'); 57 | 58 | session()->put('easypanel_lang', $lang); 59 | App::setLocale($lang); 60 | 61 | return redirect()->back(); 62 | })->name('setLang'); 63 | 64 | Route::get('translation', Manage::class) 65 | ->middleware('dynamicAcl') 66 | ->name('translation'); 67 | 68 | Route::prefix('role')->middleware('dynamicAcl')->name('role.')->group(function () { 69 | Route::get('/', \EasyPanel\Http\Livewire\Role\Lists::class)->name('lists'); 70 | Route::get('/create', Create::class)->name('create'); 71 | Route::get('/update/{role}', \EasyPanel\Http\Livewire\Role\Update::class)->name('update'); 72 | }); 73 | 74 | Route::prefix('admins')->middleware('dynamicAcl')->name('admins.')->group(function () { 75 | Route::get('/', Lists::class)->name('lists'); 76 | // Route::get('/create', \EasyPanel\Http\Livewire\Admins\Create::class)->name('create'); 77 | Route::get('/update/{admin}', Update::class)->name('update'); 78 | }); 79 | --------------------------------------------------------------------------------