added Area and Part

added two preloader sample
pull/44/head
A1Gard 5 months ago
parent 7552e86c6b
commit 5839e85f55

@ -1,16 +1,21 @@
<?php <?php
namespace App\Http\Controllers; namespace Resources\Views\Segments;
use App\Models\Part;
class Handle class Handle
{ {
public static function onAdd(){ public static function onAdd(Part $part = null)
{
} }
public static function onRemove(){ public static function onRemove(Part $part = null)
{
} }
public static function onMount(){ public static function onMount(Part $part = null)
{
} }
} }

@ -2,9 +2,11 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Models\Theme; use App\Models\Area;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\File;
use Symfony\Component\Process\Process;
class makePart extends Command class makePart extends Command
{ {
@ -15,14 +17,14 @@ class makePart extends Command
* *
* @var string * @var string
*/ */
protected $signature = 'make:part {part} {section}'; protected $signature = 'make:part {part} {segment}';
/** /**
* The console command description. * The console command description.
* *
* @var string * @var string
*/ */
protected $description = 'make theme part'; protected $description = 'make segment part';
/** /**
* Execute the console command. * Execute the console command.
@ -30,8 +32,8 @@ class makePart extends Command
public function handle() public function handle()
{ {
// //
$part = strtolower($this->argument('part')); $part = $this->argument('part');
$section = strtolower($this->argument('section')); $segment = strtolower($this->argument('segment'));
// make detail // make detail
$detail = [ $detail = [
@ -45,13 +47,13 @@ class makePart extends Command
'packages' => [], 'packages' => [],
]; ];
// check section // check section
if (!in_array($section, Theme::$sections)) { if (!in_array($segment, Area::$allSegments)) {
$this->error(__('Invalid theme section')); $this->error(__('Invalid area segment'));
return -1; return -1;
} }
$folderPath = resource_path() . '/views/segments/' . $section . '/' . $part; $folderPath = resource_path() . '/views/segments/' . $segment . '/' . ucfirst($part);
// check is exists // check is exists
@ -64,7 +66,7 @@ class makePart extends Command
File::makeDirectory($folderPath, 0755, true); File::makeDirectory($folderPath, 0755, true);
File::makeDirectory($folderPath.'/assets', 0755, true); File::makeDirectory($folderPath.'/assets', 0755, true);
$this->info('Directory created as: /theme/' . $section . '/' . $part); $this->info('Directory created as: /segments/' . $segment . '/' . ucfirst($part));
$handler = file_get_contents(__DIR__.'/data/handle.dat'); $handler = file_get_contents(__DIR__.'/data/handle.dat');
@ -83,6 +85,9 @@ DOC;
File::copy(__DIR__.'/data/screen.png',$folderPath .'/screenshot.png'); File::copy(__DIR__.'/data/screen.png',$folderPath .'/screenshot.png');
$process = new Process(['composer', 'dump-autoload']);
$process->setWorkingDirectory(base_path())->run();
$this->info(__("Theme part created successfully: [blade, js, json, scss, php, assets, screenshot]")); $this->info(__("Theme part created successfully: [blade, js, json, scss, php, assets, screenshot]"));
return 0; return 0;

@ -327,6 +327,10 @@ function lastCrump()
$title = __('Trashed') . ' ' . __($routes[count($routes) - 2]); $title = __('Trashed') . ' ' . __($routes[count($routes) - 2]);
$icon = 'ri-delete-bin-6-line'; $icon = 'ri-delete-bin-6-line';
break; break;
case 'design':
$title = __('Design') . ' ' . __($routes[count($routes) - 2]);
$icon = 'ri-paint-brush-line';
break;
default: default:
$title = __('') . ' ' . __(ucfirst($routes[count($routes) - 1])); $title = __('') . ' ' . __(ucfirst($routes[count($routes) - 1]));
$icon = 'ri-bubble-chart-line'; $icon = 'ri-bubble-chart-line';

@ -0,0 +1,72 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Area;
use App\Models\Part;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
class AreaController extends Controller
{
//
public function index()
{
$areas = Area::all('name', 'icon');
return view('admin.areas.area-list', compact('areas'));
}
public function desgin(Area $area)
{
$valids = [];
foreach ($area->segment as $seg) {
$dirs = File::directories(resource_path() . '/views/segments/' . $seg);
foreach ($dirs as $dir) {
$temp = explode('/', $dir);
$valids[] = [
'segment' => $temp[count($temp) - 2],
'part' => $temp[count($temp) - 1],
'data' => json_decode(file_get_contents($dir . '/' . $temp[count($temp) - 1] . '.json'), true)
];
}
}
return view('admin.areas.area-design', compact('area', 'valids'));
}
/**
* screenshot segment
* @param $segment
* @param $part
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function image($segment, $part)
{
return response()->file(resource_path() . '/views/segments/' . $segment . '/' . $part . '/screenshot.png', ['Content-Type' => 'image/png']);
}
public function update(Request $request, Area $area)
{
// return $request->all();
foreach ($request->input('parts',[]) as $item) {
$data = json_decode($item);
if ($data->id == null){
// create
$part = new Part();
$part->area_id = $area->id;
$part->segment = $data->segment;
$part->part = $data->part;
$part->save();
}else{
$part = Part::whereId($data->id)->first();
$part->segment = $data->segment;
$part->part = $data->part;
$part->save();
}
}
logAdmin(__METHOD__,__CLASS__,$area->id);
return redirect()->back()->with(['message' => __('area :NAME of website updated',['NAME' => $area->name])]);
}
}

@ -20,6 +20,7 @@ class GfxController extends Controller
$g->value = $gfx; $g->value = $gfx;
$g->save(); $g->save();
} }
logAdmin(__METHOD__,__CLASS__,null); logAdmin(__METHOD__,__CLASS__,null);
\Artisan::call('client'); \Artisan::call('client');
return redirect()->back()->with(['message' => __('GFX of website updated')]); return redirect()->back()->with(['message' => __('GFX of website updated')]);

@ -0,0 +1,60 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Area extends Model
{
// use HasFactory;
public static $allSegments = [
'ads',
'attachment',
'attachments',
'attachmentsList',
'card',
'category',
'clip',
'clips',
'comments',
'compare',
'customer',
'floats',
'footer',
'galleries',
'gallery',
'group',
'groups',
'index',
'invoice',
'login',
'menu',
'parallax',
'preloader',
'product',
'products',
'questions',
'search',
'search',
'top',
];
protected $casts = [
'segments',
];
public function getSegmentAttribute()
{
return json_decode($this->valid_segments,true);
}
public function getRouteKeyName(){
return 'name';
}
public function parts(){
return $this->hasMany(Part::class);
}
}

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Part extends Model
{
use HasFactory;
}

@ -0,0 +1,66 @@
<?php
namespace App\Observers;
use App\Models\Part;
class PartObsever
{
/**
* Handle the Part "created" event.
*/
public function created(Part $part): void
{
// run on add for new
$className= ucfirst($part->part);
$handle = "\\Resources\\Views\\Segments\\$className";
$handle::onAdd($part);
}
/**
* Handle the Part "updated" event.
*/
public function updated(Part $part): void
{
// remove old part add new part
if ($part->isDirty('part')){
$className = ucfirst($part->getOriginal('part'));
$handle = "\\Resources\\Views\\Segments\\$className";
$handle::onRemove($part);
$className = $part->part;
$className= ucfirst($part->part);
$handle = "\\Resources\\Views\\Segments\\$className";
$handle::onAdd($part);
}
}
/**
* Handle the Part "deleted" event.
*/
public function deleted(Part $part): void
{
// remove part
$className= ucfirst($part->part);
$handle = "\\Resources\\Views\\Segments\\$className";
$handle::onRemove($part);
}
/**
* Handle the Part "restored" event.
*/
public function restored(Part $part): void
{
//
}
/**
* Handle the Part "force deleted" event.
*/
public function forceDeleted(Part $part): void
{
//
}
}

@ -3,6 +3,10 @@
namespace App\Providers; namespace App\Providers;
use App\Helpers\TDate; use App\Helpers\TDate;
use App\Http\Middleware\Acl; use App\Http\Middleware\Acl;
use App\Models\Area;
use App\Models\Part;
use App\Observers\AreaObsever;
use App\Observers\PartObsever;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Pagination\Paginator; use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Blade;
@ -44,6 +48,8 @@ class AppServiceProvider extends ServiceProvider
} }
}); });
Part::observe(PartObsever::class);
} }
} }

@ -43,6 +43,9 @@
}, },
"files": [ "files": [
"app/Helpers/Helper.php" "app/Helpers/Helper.php"
],
"classmap": [
"resources/views/segments"
] ]
}, },
"autoload-dev": { "autoload-dev": {

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('areas', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->tinyInteger('max')->default(1);
$table->string('icon')->nullable();
$table->json('valid_segments');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('areas');
}
};

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('parts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('area_id');
$table->integer('sort')->default(0);
$table->string('segment');
$table->string('part');
$table->json('data')->default('[]');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('parts');
}
};

@ -0,0 +1,44 @@
<?php
namespace Database\Seeders;
use App\Models\Area;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class AreaSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
$areas = [
[
'name' => 'preloader',
'valid_segments' => json_encode(
['preloader']
),
'max' => 1,
'icon' => 'ri-loader-2-line',
],
[
'name' => 'top',
'valid_segments' => json_encode(
['top']
),
'max' => 1,
'icon' => 'ri-layout-top-2-line',
],
];
foreach ($areas as $area){
$a = new Area();
$a->name = $area['name'];
$a->max = $area['max'];
$a->valid_segments = $area['valid_segments'];
$a->icon = $area['icon'];
$a->save();
}
}
}

@ -34,6 +34,8 @@ class DatabaseSeeder extends Seeder
CommentSeeder::class, CommentSeeder::class,
SettingSeeder::class, SettingSeeder::class,
GfxSeeder::class, GfxSeeder::class,
AreaSeeder::class,
PartSeeder::class,
] ]
); );
} }

@ -0,0 +1,26 @@
<?php
namespace Database\Seeders;
use App\Models\Area;
use App\Models\Part;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class PartSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
//
$part = new Part();
$part->segment = 'preloader';
$part->part = 'PreloaderImage';
$part->area_id = Area::where('name','preloader')->first()->id;
$part->save();
}
}

@ -90,6 +90,9 @@ app.component('morph-selector', MorphSelector);
import Gfxer from "./components/Gfxer.vue"; import Gfxer from "./components/Gfxer.vue";
app.component('gfxer', Gfxer); app.component('gfxer', Gfxer);
import AreaDesginer from "./components/AreaDesginer.vue";
app.component('area-designer', AreaDesginer);
/** /**
* The following block of code may be used to automatically register your * The following block of code may be used to automatically register your

@ -0,0 +1,83 @@
<template>
<div id="area-designer">
<div class="card mt-2" v-for="(part,p) in partsData">
<div class="card-header">
Part {{p+1}}
</div>
<div class="part-body">
<div class="row">
<template v-for="(valid,i) in valids">
<div @click="changePart(p,valid.segment,valid.part)" :class="`col-md-3 `+(valid.data.name == part.part?'selected-part':'can-select')" >
<img class="img-fluid mt-2" :src="imageLink+'/'+valid.segment+'/'+valid.part" alt="screeshot">
{{valid.part}} [v{{valid.data.version}}]
</div>
</template>
</div>
<input type="hidden" name="parts[]" :value="JSON.stringify(part)" class="form-control">
</div>
</div>
<div v-if="parts.length < parseInt(area.max)" class="p-2">
<div class="btn btn-primary w-100" @click="addPart">
<i class="ri-add-line"></i>
</div>
</div>
</div>
</template>
<script>
export default {
name: "area-designer",
components: {},
data: () => {
return {
partsData:[],
}
},
props: {
valids:{
default:[],
type: Array,
},
parts:{
default:[],
type: Array,
},
area:{
required: true,
type: Object,
},
imageLink:{
required: true,
}
},
mounted() {
this.partsData = this.parts;
},
computed: {},
methods: {
changePart(p,segment,part){
this.partsData[p].segment = segment;
this.partsData[p].part = part;
},
addPart(){
this.partsData.push({
id: null,
segment: this.valids[0].segment,
part: this.valids[0].part,
});
}
}
}
</script>
<style scoped>
#area-designer {
}
.selected-part{
background: #32CD3233;
}
.can-select{
cursor: pointer;
}
</style>

@ -2,11 +2,11 @@
// IF YOU WANT ADD ANY CODE CREATE NEW SCSS INTO client-custom // IF YOU WANT ADD ANY CODE CREATE NEW SCSS INTO client-custom
:root{ :root{
--xshop-background:#eeeeee; --xshop-background:#eeeeee;
--xshop-primary:#81c700; --xshop-primary:#6e0000;
--xshop-secondary:#00eeff; --xshop-secondary:#ff0000;
--xshop-text:#111111; --xshop-text:#111111;
--border-radius:7px; --border-radius:7px;
--xshop-shadow:5px 10px 31px #ff00f7; --xshop-shadow:2px 2px 4px #777777;
} }
@import "client-custom/assetsNode"; @import "client-custom/assetsNode";

@ -178,3 +178,19 @@ a.btn,a.action-btn,a.circle-btn{
} }
.area-list-item{
background: #00000022;
height: 125px;
text-align: center;
display: block;
color: $text-muted;
&:hover{
color: lighten($primary-color-panel,10);
}
i{
font-size: 45px;
display: block;
margin: 1rem auto;
}
}

@ -0,0 +1,45 @@
@extends('layouts.app')
@section('title')
{{__("Design :AREA",['AREA' => $area->name])}}
@endsection
@section('content')
<form action="{{route('admin.area.update',$area->name)}}" method="post">
@csrf
<div class="general-form mb-5">
<h1>
{{__("Design :AREA",['AREA' => $area->name])}} <i class="{{$area->icon}}"></i>
</h1>
<area-designer
image-link="{{route('admin.area.image',['',''])}}"
:parts='@json($area->parts)'
:valids='@json($valids)'
:area='@json($area)'
></area-designer>
{{-- <div class="row">--}}
{{-- @foreach($valids as $valid)--}}
{{-- <div class="col-md-3">--}}
{{-- <img class="img-fluid" src="{{route('admin.area.image',[$valid['segment'],$valid['part']])}}" alt="{{$valid['segment'].'.'.$valid['part']}}">--}}
{{-- <h5 class="mt-2 text-center">--}}
{{-- {{$valid['data']['name']}} [v{{$valid['data']['version']}}]--}}
{{-- </h5>--}}
{{-- </div>--}}
{{-- @endforeach--}}
{{-- </div>--}}
</div>
<button
data-link="{{getRoute('sort-save')}}"
id="save-sort"
class="action-btn circle-btn"
data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-custom-class="custom-tooltip"
data-bs-title="{{__("Save")}}"
>
<i class="ri-save-2-line"></i>
</button>
</form>
@endsection

@ -0,0 +1,17 @@
@extends('layouts.app')
@section('title')
{{__("Area desgin")}}
@endsection
@section('content')
<div class="row">
@foreach($areas as $area)
<div class="col-md-4">
<a class="area-list-item" href="{{route('admin.area.design',$area->name)}}">
<i class="{{$area->icon}}"></i>
{{__(ucfirst($area->name))}}
</a>
</div>
@endforeach
</div>
@endsection

@ -135,9 +135,9 @@
</a> </a>
</li> </li>
<li> <li>
<a href=""> <a href="{{route('admin.area.index')}}">
<i class="ri-paint-brush-line"></i> <i class="ri-paint-brush-line"></i>
{{__("Design")}} {{__("Area design")}}
</a> </a>
</li> </li>
</ul> </ul>

@ -0,0 +1,10 @@
{
"name": "PreloaderCircle",
"version": "1.0",
"author": "xStack",
"email": "xshop@xstack.ir",
"license": "GPL-3.0-or-later",
"url": "https:\/\/xstack.ir",
"author_url": "https:\/\/4xmen.ir",
"packages": []
}

@ -0,0 +1,21 @@
<?php
namespace Resources\Views\Segments;
use App\Models\Part;
class PreloaderCircle
{
public static function onAdd(Part $part = null)
{
\Log::info('added '.$part->part.' on '.$part->segment);
}
public static function onRemove(Part $part = null)
{
\Log::info('remove '.$part->part.' on '.$part->segment);
}
public static function onMount(Part $part = null)
{
\Log::info('monted '.$part->part.' on '.$part->segment);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

@ -0,0 +1,10 @@
{
"name": "PreloaderImage",
"version": "1.0",
"author": "xStack",
"email": "xshop@xstack.ir",
"license": "GPL-3.0-or-later",
"url": "https:\/\/xstack.ir",
"author_url": "https:\/\/4xmen.ir",
"packages": []
}

@ -0,0 +1,21 @@
<?php
namespace Resources\Views\Segments;
use App\Models\Part;
class PreloaderImage
{
public static function onAdd(Part $part = null)
{
\Log::info('added '.$part->part.' on '.$part->segment);
}
public static function onRemove(Part $part = null)
{
\Log::info('remove '.$part->part.' on '.$part->segment);
}
public static function onMount(Part $part = null)
{
\Log::info('monted '.$part->part.' on '.$part->segment);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

@ -272,18 +272,24 @@ Route::prefix(config('app.panel.prefix'))->name('admin.')->group(
Route::post('update', [\App\Http\Controllers\Admin\GfxController::class, "update"])->name('update'); Route::post('update', [\App\Http\Controllers\Admin\GfxController::class, "update"])->name('update');
} }
); );
Route::prefix('area')->name('area.')->group(
function () {
Route::get('index', [\App\Http\Controllers\Admin\AreaController::class, "index"])->name('index');
Route::get('design/{area}', [\App\Http\Controllers\Admin\AreaController::class, "desgin"])->name('design');
Route::get('image/{segment}/{part}', [\App\Http\Controllers\Admin\AreaController::class, "image"])->name('image');
// Route::post('store', [\App\Http\Controllers\Admin\SettingController::class, "store"])->name('store');
Route::post('update/{area}', [\App\Http\Controllers\Admin\AreaController::class, "update"])->name('update');
}
);
}); });
}); });
Route::get('test',function (){ Route::get('test',function (){
$c = new \App\Models\Contact();
$c->name = 'mamali'; // return \Resources\Views\Segments\PreloaderCircle::onAdd();
$c->email = 'mamali@yahoo.com';
$c->mobile = '091212344557'; Log::info('--test--');
$c->body = 'test test contact';
$c->subject = ' this a subject';
$c->save();
return \App\Helpers\PersianFaker::color();
}); });

Loading…
Cancel
Save