diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 398721f..b43bf3e 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1,15 +1,15 @@ "πŸ‡ΏπŸ‡¦", // Afrikaans "sq" => "πŸ‡¦πŸ‡±", // Albanian "am" => "πŸ‡ͺπŸ‡Ή", // Amharic @@ -76,7 +76,7 @@ function getEmojiLanguagebyCode($lang) { "uz" => "πŸ‡ΊπŸ‡Ώ", // Uzbek "vi" => "πŸ‡»πŸ‡³", // Vietnamese "cy" => "πŸ‡¬πŸ‡§" // Welsh - ); + ]; $lang = strtolower($lang); if (array_key_exists($lang, $languages)) { return $languages[$lang]; @@ -84,3 +84,55 @@ function getEmojiLanguagebyCode($lang) { return "❓"; } } + +/** + * has route as named we want this model? + * @param $name string + * @return bool + */ + +function hasRoute($name) +{ + // create route + $cRuote = str_replace('index', $name, request()->route()->getName()); + if (\Illuminate\Support\Facades\Route::has($cRuote)) { + return true; + } else { + return false; + } +} + +/** + * get named route url + * @param $name string + * @param $args array + * @return string|null + */ +function getRoute($name,$args = []) +{ + // create route + $cRuote = str_replace('index', $name, request()->route()->getName()); + if (\Illuminate\Support\Facades\Route::has($cRuote)) { + return \route($cRuote,$args); + } else { + return null; + } +} + + +/** + * make sort link suffix + * @param $col string + * @return string + */ +function sortSuffix($col){ + if (request()->sort == $col){ + if (request('sortType','asc') == 'desc'){ + return '&sortType=asc'; + }else{ + return '&sortType=desc'; + } + }else{ + return ''; + } +} diff --git a/app/Helpers/TDate.php b/app/Helpers/TDate.php index 6bc5f2e..b3889f2 100644 --- a/app/Helpers/TDate.php +++ b/app/Helpers/TDate.php @@ -1,6 +1,7 @@ paginate(config('app.panel.page_count'), array_merge($this->extra_cols, $this->cols)); + $cols = $this->cols; + return view($this->listView, compact('items', 'cols')); + } + + protected function makeSortAndFilter() + { + if (!\request()->has('sort') || !in_array(\request('sort'), $this->cols)) { + $query = $this->model::orderByDesc('id'); + } else { + $query = $this->model::orderBy(\request('sort'), \request('sortType', 'asc')); + } + return $query; + } + /** * Display a listing of the resource. */ public function index() { - // - $items = $this->model::orderByDesc('id')->paginate(config('app.panel.page_count')); - return view($this->listView,compact('items')); + + $query = $this->makeSortAndFilter(); + return $this->showList($query); + } /** @@ -47,7 +69,7 @@ class XController extends Controller /** * Display the specified resource. */ - public function show( $user) + public function show($user) { // } @@ -63,7 +85,7 @@ class XController extends Controller /** * Update the specified resource in storage. */ - public function update(Request $request, $user) + public function update(Request $request, $user) { // } @@ -75,4 +97,14 @@ class XController extends Controller { // } + + + /** + * Show list of trashed + */ + public function trashed() + { + $query = User::onlyTrashed(); + return $this->showList($query); + } } diff --git a/app/Models/Menu.php b/app/Models/Menu.php index fb8b774..6988928 100644 --- a/app/Models/Menu.php +++ b/app/Models/Menu.php @@ -13,5 +13,5 @@ class Menu extends Model public function menuItems() { return $this->hasMany(MenuItem::class, 'menu_id', 'id'); - }; + } } diff --git a/app/Models/Post.php b/app/Models/Post.php index 490ba65..74acbd6 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -89,16 +89,16 @@ class Post extends Model implements HasMedia return $this->morphMany(Comment::class, 'commentable')->where('status', 1); } - public function toArray() - { - return [ - 'id' => $this->id, - 'title' => $this->title, - 'subtitle' => $this->subtitle, - 'body' => $this->body, - 'categories' => $this->categories->implode(' ') ?? null, - 'author' => $this->author->name ?? null, - 'tags' => $this->tags->implode(' ') ?? null, - ]; - } +// public function toArray() +// { +// return [ +// 'id' => $this->id, +// 'title' => $this->title, +// 'subtitle' => $this->subtitle, +// 'body' => $this->body, +// 'categories' => $this->categories->implode(' ') ?? null, +// 'author' => $this->author->name ?? null, +// 'tags' => $this->tags->implode(' ') ?? null, +// ]; +// } } diff --git a/app/Models/User.php b/app/Models/User.php index 43e9a83..311c0b6 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,13 +4,14 @@ namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { - use HasFactory, Notifiable, HasRoles; + use HasFactory, Notifiable, HasRoles, SoftDeletes; static $roles = ['DEVELOPER', 'ADMIN', 'USER']; @@ -47,4 +48,8 @@ class User extends Authenticatable 'password' => 'hashed', ]; } + + public function posts(){ + return $this->hasMany(Post::class); + } } diff --git a/app/Models/user.php b/app/Models/user.php deleted file mode 100644 index 95c7dbb..0000000 --- a/app/Models/user.php +++ /dev/null @@ -1,11 +0,0 @@ -PDate($format, self::this()->timestamp); }); + + } } diff --git a/app/Providers/BladeServiceProvider.php b/app/Providers/BladeServiceProvider.php new file mode 100644 index 0000000..1bd915f --- /dev/null +++ b/app/Providers/BladeServiceProvider.php @@ -0,0 +1,38 @@ +total(); + \$currentPage = \$items->currentPage(); + \$perPage = \$items->perPage(); + \$from = (\$currentPage - 1) * \$perPage + 1; + \$to = min(\$currentPage * \$perPage, \$total); + + echo \"(\$from | \$to | \$total) \"; ?>"; + }); + } +} diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 002013b..326249a 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -2,5 +2,6 @@ return [ App\Providers\AppServiceProvider::class, + App\Providers\BladeServiceProvider::class, Spatie\Permission\PermissionServiceProvider::class, ]; diff --git a/composer.json b/composer.json index 5c1ed76..7a1a723 100644 --- a/composer.json +++ b/composer.json @@ -34,15 +34,14 @@ "spatie/laravel-ignition": "^2.4" }, "autoload": { - "files": [ - "app/Helpers/Helper.php", - "app/Helpers/TDate.php" - ], "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", "Database\\Seeders\\": "database/seeders/" - } + }, + "files": [ + "app/Helpers/Helper.php" + ] }, "autoload-dev": { "psr-4": { diff --git a/config/app.php b/config/app.php index cfa026b..9a691f7 100644 --- a/config/app.php +++ b/config/app.php @@ -1,4 +1,6 @@ Facade::defaultAliases()->merge([ + // 'Example' => App\Facades\Example::class, + ])->toArray(), + + + 'providers' => ServiceProvider::defaultProviders()->merge([ + /* + * Package Service Providers... + */ + + /* + * Application Service Providers... + */ + App\Providers\AppServiceProvider::class, + Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, + Translator\Framework\TranslatorServiceProvider::class, + \App\Providers\BladeServiceProvider::class, + + ])->toArray(), ]; diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 584104c..990afac 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -27,6 +27,8 @@ class UserFactory extends Factory 'name' => fake()->name(), 'email' => fake()->unique()->safeEmail(), 'email_verified_at' => now(), + 'mobile' => '0912'.rand(1000000,9999999), + 'role' => 'USER', 'password' => static::$password ??= Hash::make('password'), 'remember_token' => Str::random(10), ]; diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index aedfa6f..06525d6 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -22,6 +22,7 @@ return new class extends Migration $table->enum('role',\App\Models\User::$roles)->default('USER'); $table->rememberToken(); $table->timestamps(); + $table->softDeletes(); }); Schema::create('password_reset_tokens', function (Blueprint $table) { diff --git a/database/migrations/2024_05_07_123414_create_posts_table.php b/database/migrations/2024_05_07_123414_create_posts_table.php index bca0219..293c9d6 100644 --- a/database/migrations/2024_05_07_123414_create_posts_table.php +++ b/database/migrations/2024_05_07_123414_create_posts_table.php @@ -17,7 +17,7 @@ return new class extends Migration $table->string('slug')->unique(); $table->string('subtitle', 4096); $table->text('body'); - $table->unsignedBigInteger('category_id'); + $table->unsignedBigInteger('group_id'); $table->unsignedBigInteger('user_id'); $table->unsignedTinyInteger('status')->default(0); $table->boolean('is_breaking')->default(0); @@ -31,7 +31,8 @@ return new class extends Migration $table->foreign('user_id') ->references('id')->on('users'); - $table->foreign('category_id') + + $table->foreign('group_id') ->references('id')->on('groups'); }); diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 66c6cc0..0e46ac4 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -1,10 +1,8 @@ assignRole('user'); $user->save(); + User::factory(50)->create(); + } } diff --git a/resources/js/app.js b/resources/js/app.js index 913799b..d7dbd06 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -16,6 +16,7 @@ import './bootstrap'; import { createApp } from 'vue'; import './panel/raw.js'; import './panel/navbar.js'; +import './panel/list-checkboxs.js'; /** * Next, we will create a fresh Vue application instance. You may then begin diff --git a/resources/js/panel/list-checkboxs.js b/resources/js/panel/list-checkboxs.js new file mode 100644 index 0000000..666b72b --- /dev/null +++ b/resources/js/panel/list-checkboxs.js @@ -0,0 +1,88 @@ +function clearSelection() +{ + if (window.getSelection) {window.getSelection().removeAllRanges();} + else if (document.selection) {document.selection.empty();} +} + +window.addEventListener('load',function () { + let chkall = document.querySelectorAll(".chkall"); + + document.querySelector('#toggle-select').addEventListener('click',function () { + let checkboxes = document.querySelectorAll(".chkbox"); + checkboxes.forEach(function(checkbox) { + if (!checkbox.checked){ + checkbox.checked = true; + checkbox.setAttribute("checked", ""); + }else{ + checkbox.checked = false; + checkbox.removeAttribute("checked"); + } + }); + }); +// Attach an event listener for "change" and "click" events + chkall.forEach(function(chkall) { + chkall.addEventListener("change", handleCheckboxChange); + chkall.addEventListener("click", handleCheckboxChange); + }); + + function handleCheckboxChange() { + let isChecked = this.checked; + let table = this.closest("table"); + + if (isChecked) { + // Check all checkboxes in the table + let checkboxes = table.querySelectorAll(".chkbox"); + checkboxes.forEach(function(checkbox) { + checkbox.checked = true; + checkbox.setAttribute("checked", ""); + }); + } else { + // Uncheck all checkboxes in the table + let checkboxes = table.querySelectorAll(".chkbox"); + checkboxes.forEach(function(checkbox) { + checkbox.checked = false; + checkbox.removeAttribute("checked"); + }); + } + } + + + + // select with shift button + const chkboxes = document.querySelectorAll('.chkbox'); + let lastChecked = null; + + chkboxes.forEach(chkbox => { + chkbox.addEventListener('click', handleCheckboxClick); + chkbox.parentNode.querySelector('label').addEventListener('click', handleCheckboxClick); + }); + + function handleCheckboxClick(e) { + clearSelection(); + + let self = this; + if (e.target.tagName === 'LABEL'){ + self = e.target.parentNode.querySelector('input'); + } + if (!lastChecked) { + lastChecked = self; + return; + } + + if (e.shiftKey) { + const start = Array.from(chkboxes).indexOf(self); + const end = Array.from(chkboxes).indexOf(lastChecked); + const range = Array.from(chkboxes).slice(Math.min(start, end) + 1, Math.max(start, end) ); + + range.forEach(chkbox => { + chkbox.checked = lastChecked.checked; + }); + + } + + lastChecked = self; + + } + +}); + diff --git a/resources/sass/_common.scss b/resources/sass/_common.scss deleted file mode 100644 index d9fea0a..0000000 --- a/resources/sass/_common.scss +++ /dev/null @@ -1,20 +0,0 @@ -.circle-btn{ - width: 75px; - height: 75px; - border-radius: 50%; - background: rgba(139, 0, 139, 0.86); - backdrop-filter: blur(4px); - border: 0; - box-shadow: 0px 3px 5px #11111177, inset 0 0 0 0 darkred; - user-select: none; - cursor: pointer; - transition: 500ms; - &:hover{ - box-shadow: 0px 3px 5px #11111177, inset 0 0 0 40px darkred; - } -} - -.custom-tooltip { - --bs-tooltip-bg: var(--bs-indigo); - --bs-tooltip-color: var(--bs-white); -} diff --git a/resources/sass/app.scss b/resources/sass/app.scss index 221d094..e72cb9c 100644 --- a/resources/sass/app.scss +++ b/resources/sass/app.scss @@ -2,7 +2,7 @@ @import 'vazirmatn/Vazirmatn-font-face.css'; @import "remixicon/fonts/remixicon.css"; // Variables -@import 'variables'; +@import 'panel/variables'; // Bootstrap @import 'bootstrap/scss/bootstrap'; @@ -47,7 +47,7 @@ a{ >aside{ background-image: url("../images/pattern.png"); - background-color: #282c34; + background-color: lighten($body-bg,7); } &.sided{ grid-template-columns:50px 250px 1fr; @@ -58,7 +58,9 @@ a{ } -@import "common"; -@import "raw"; -@import "fix"; -@import "navbar"; +@import "panel/common"; +@import "panel/raw"; +@import "panel/fix"; +@import "panel/navbar"; +@import "panel/breadcrumbs"; +@import "panel/item-list"; diff --git a/resources/sass/panel/_breadcrumbs.scss b/resources/sass/panel/_breadcrumbs.scss new file mode 100644 index 0000000..9706743 --- /dev/null +++ b/resources/sass/panel/_breadcrumbs.scss @@ -0,0 +1,5 @@ +#panel-breadcrumb{ + height: 50px; + background: #00000033; + margin-bottom: 1rem; +} diff --git a/resources/sass/panel/_common.scss b/resources/sass/panel/_common.scss new file mode 100644 index 0000000..05f64ab --- /dev/null +++ b/resources/sass/panel/_common.scss @@ -0,0 +1,53 @@ +body{ + background: $body-bg; +} + +.circle-btn{ + width: 75px; + height: 75px; + border-radius: 50%; + background: $secondary-color-panel; + backdrop-filter: blur(4px); + border: 0; + box-shadow: 0px 3px 5px #11111177, inset 0 0 0 0 darkred; + user-select: none; + cursor: pointer; + transition: 500ms; + &:hover{ + box-shadow: 0px 3px 5px #11111177, inset 0 0 0 40px darkred; + } +} + +.custom-tooltip { + --bs-tooltip-bg: var(--bs-indigo); + --bs-tooltip-color: var(--bs-white); +} + +.grid-equal { + display: grid; + grid-auto-columns: minmax(0, 1fr); + grid-auto-flow: column; +} + +a.btn,a.action-btn,a.circle-btn{ + &:hover{ + color:white; + i{ + color: white; + } + } + +} + +.action-btn{ + display: block; + font-size: 47px; + text-align: center; + i{ + color: white; + } + position: fixed; + inset-inline-end: 1rem; + bottom: 1rem; +} + diff --git a/resources/sass/_fix.scss b/resources/sass/panel/_fix.scss similarity index 68% rename from resources/sass/_fix.scss rename to resources/sass/panel/_fix.scss index 5385247..53447f0 100644 --- a/resources/sass/_fix.scss +++ b/resources/sass/panel/_fix.scss @@ -5,7 +5,7 @@ border-color: #bc86fe; .card{ background-color: rgba(var(--bs-body-bg),.5); - background-image: url("../images/pattern.png"); + background-image: url("../../images/pattern.png"); backdrop-filter: blur(4px); box-shadow: -2px -2px 7px #560000, 2px 2px 7px #5e00b5; } @@ -27,3 +27,10 @@ a,a:visited{ color: #ff0067; } } + +.pagination{ + --bs-pagination-active-bg: #6e0000 ; + --bs-pagination-active-border-color: #810000; + --bs-pagination-color: #cb00a5; + --bs-pagination-hover-color: red; +} diff --git a/resources/sass/panel/_item-list.scss b/resources/sass/panel/_item-list.scss new file mode 100644 index 0000000..01e6fde --- /dev/null +++ b/resources/sass/panel/_item-list.scss @@ -0,0 +1,86 @@ +.item-list { + overflow: hidden; + background: $lighter-color; + //margin: 0 1rem; + border-radius: 4px; + + h1 { + font-size: 25px; + padding: 1rem; + font-weight: 200; + margin: 0; + } + + .item-search { + form { + padding: 1rem; + } + } +} + +.table-list { + width: 100%; + tr{ + + th{ + background-color: #00000033; + background-image: url("../images/pattern.png"); + } + + td,th{ + &:first-child{ + width: 100px; + } + &:last-child{ + text-align: center; + } + vertical-align: center; + padding: .5rem; + border-bottom: 1px solid #ffffff11; + input{ + margin: .5rem 1rem ; + } + a{ + b{ + color: white; + } + } + } + td{ + label{ + padding: .45rem 1rem ; + cursor: pointer; + border-radius: 3px; + } + input:checked + label{ + background: lighten($primary-color-panel,10); + } + input{ + display: none; + } + } + + &:nth-child(even) td{ + background: #00000010; + } + + + &:hover{ + td{ + background-color: #00000044; + background-image: url("../images/pattern.png"); + } + } + + } + + tfoot th{ + border-bottom: 0; + ul.pagination{ + margin: 0; + justify-content: center; + } + } +} + + diff --git a/resources/sass/_navbar.scss b/resources/sass/panel/_navbar.scss similarity index 100% rename from resources/sass/_navbar.scss rename to resources/sass/panel/_navbar.scss diff --git a/resources/sass/_raw.scss b/resources/sass/panel/_raw.scss similarity index 97% rename from resources/sass/_raw.scss rename to resources/sass/panel/_raw.scss index d8fdad0..038347f 100644 --- a/resources/sass/_raw.scss +++ b/resources/sass/panel/_raw.scss @@ -4,6 +4,7 @@ justify-content: center; align-items: center; width: 100%; + position: relative; #raw-form{ max-width: 95%; width: 450px; diff --git a/resources/sass/_variables.scss b/resources/sass/panel/_variables.scss similarity index 61% rename from resources/sass/_variables.scss rename to resources/sass/panel/_variables.scss index aea83ec..a306f06 100644 --- a/resources/sass/_variables.scss +++ b/resources/sass/panel/_variables.scss @@ -1,8 +1,10 @@ // Body -$body-bg: #f8fafc; +$body-bg: #1b223a; // Typography $font-family-sans-serif: 'Vazirmatn', sans-serif; $font-size-base: 0.9rem; $line-height-base: 1.6; $primary-color-panel: #6e0000; +$secondary-color-panel: rgba(139, 0, 139, 0.86) ; +$lighter-color: #282d47; diff --git a/resources/views/admin/templates/panel-list-template.blade.php b/resources/views/admin/templates/panel-list-template.blade.php new file mode 100644 index 0000000..c004785 --- /dev/null +++ b/resources/views/admin/templates/panel-list-template.blade.php @@ -0,0 +1,192 @@ +@extends('layouts.app') + +@section('content') +
+
+ + {{-- list side bar start--}} +
+
+
+
+

+ @yield('list-title') +

+
+
+ @if(hasRoute('trashed')) + + + + @endif +
+
+
+
+ + +
+ @yield('filter') +
+
+
+ {{-- list side bar end--}} + + + {{-- list content start--}} +
+
+ + + + + + @foreach($cols as $col) + + @endforeach + @yield('table-head') + + + + + @foreach($items as $item) + + + @foreach($cols as $k => $col) + @if($k == 0 && hasRoute('edit')) + + @else + + @endif + @endforeach + @yield('table-body') + + + @endforeach + + + + {{-- pagination and toggle button start --}} + + + + + + {{-- pagination and toggle button end --}} +
+
+ +
+
+ + {{__($col)}} + + + {{__("Totol")}}: + {{$items->total()}} +
+ + + + + + {{$item->name}} + + + + {{$item->$col}} + + @if(hasRoute('destroy')) + + + + @endif + @if(hasRoute('edit')) + + + + @endif + @if(hasRoute('show')) + + + + @endif + @yield('list-btn') +
+
+
+
+ +
+
+
+ {{$items->withQueryString()->links()}} +
+
+
+ @paginated($items) +
+ +
+
+
+
+
+ {{-- list content end--}} +
+
+ + @if(hasRoute('create')) + + + + @endif +@endsection diff --git a/resources/views/admin/users/user-list.blade.php b/resources/views/admin/users/user-list.blade.php index b3d9bbc..cb00944 100644 --- a/resources/views/admin/users/user-list.blade.php +++ b/resources/views/admin/users/user-list.blade.php @@ -1 +1,12 @@ - + {{__("Users list")}} +@endsection +@section('title') + {{__("Users list")}} | +@endsection +@section('filter') + +@endsection diff --git a/resources/views/components/panel-breadcrumb.blade.php b/resources/views/components/panel-breadcrumb.blade.php new file mode 100644 index 0000000..3f850ae --- /dev/null +++ b/resources/views/components/panel-breadcrumb.blade.php @@ -0,0 +1,3 @@ + diff --git a/resources/views/components/panel-side-navbar.blade.php b/resources/views/components/panel-side-navbar.blade.php index 198f956..a427172 100644 --- a/resources/views/components/panel-side-navbar.blade.php +++ b/resources/views/components/panel-side-navbar.blade.php @@ -183,7 +183,7 @@