mirror of https://github.com/4xmen/xshop.git
parent
7552e86c6b
commit
5839e85f55
@ -1,16 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
namespace Resources\Views\Segments;
|
||||
|
||||
use App\Models\Part;
|
||||
|
||||
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