mirror of https://github.com/4xmen/xshop.git
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)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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])]);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
@ -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
|
@ -0,0 +1 @@
|
|||||||
|
<div id='PreloaderCircle'></div>
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
#PreloaderCircle {
|
||||||
|
// scss
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
@ -0,0 +1 @@
|
|||||||
|
<div id='PreloaderImage'></div>
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
#PreloaderImage {
|
||||||
|
// scss
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
Loading…
Reference in New Issue