added setting to panel

pull/44/head
A1Gard 5 months ago
parent 58bc5e97d1
commit 22a302f975

@ -1,6 +1,7 @@
<?php <?php
use App\Helpers; use App\Helpers;
use App\Models\Setting;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
@ -430,10 +431,11 @@ function getAdminRoutes()
* @param $model \Illuminate\Database\Eloquent\Model * @param $model \Illuminate\Database\Eloquent\Model
* @return void * @return void
*/ */
function modelWithCustomAttrs($model){ function modelWithCustomAttrs($model)
{
$data = $model->toArray(); $data = $model->toArray();
$attrs = $model->getMutatedAttributes(); $attrs = $model->getMutatedAttributes();
$attrs = array_diff($attrs,['translations']); $attrs = array_diff($attrs, ['translations']);
foreach ($attrs as $attr) { foreach ($attrs as $attr) {
$data[$attr] = $model->getAttribute($attr); $data[$attr] = $model->getAttribute($attr);
} }
@ -445,7 +447,8 @@ function modelWithCustomAttrs($model){
* get max size for upload * get max size for upload
* @return int * @return int
*/ */
function getMaxUploadSize() { function getMaxUploadSize()
{
$uploadMaxSize = returnBytes(ini_get('upload_max_filesize')); $uploadMaxSize = returnBytes(ini_get('upload_max_filesize'));
$postMaxSize = returnBytes(ini_get('post_max_size')); $postMaxSize = returnBytes(ini_get('post_max_size'));
@ -458,10 +461,11 @@ function getMaxUploadSize() {
* @param $val * @param $val
* @return float|int|string * @return float|int|string
*/ */
function returnBytes($val) { function returnBytes($val)
$last = strtolower($val[strlen($val)-1]); {
$val = trim(strtolower($val),'kgm'); $last = strtolower($val[strlen($val) - 1]);
switch($last) { $val = trim(strtolower($val), 'kgm');
switch ($last) {
// The 'G' modifier is available since PHP 5.1.0 // The 'G' modifier is available since PHP 5.1.0
case 'g': case 'g':
$val *= 1024 * 1024 * 1024; $val *= 1024 * 1024 * 1024;
@ -480,7 +484,8 @@ function returnBytes($val) {
* @param $size * @param $size
* @return string * @return string
*/ */
function formatFileSize($size) { function formatFileSize($size)
{
if ($size < 1024) { if ($size < 1024) {
return $size . ' bytes'; return $size . ' bytes';
} elseif ($size < 1048576) { } elseif ($size < 1048576) {
@ -498,7 +503,8 @@ function formatFileSize($size) {
* @param $length * @param $length
* @return string * @return string
*/ */
function generateUniqueID($length = 8) { function generateUniqueID($length = 8)
{
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$uniqueID = ''; $uniqueID = '';
@ -510,17 +516,91 @@ function generateUniqueID($length = 8) {
return $uniqueID; return $uniqueID;
} }
/**
* comment status to bypass blade error
* @return array[]
*/
function commentStatuses() function commentStatuses()
{ {
return [ return [
['name' => __("Approved"), 'id' => '1' ], ['name' => __("Approved"), 'id' => '1'],
['name' => __("Rejected"), 'id' => '-1' ], ['name' => __("Rejected"), 'id' => '-1'],
['name' => __("Pending"), 'id' => '0' ] ['name' => __("Pending"), 'id' => '0']
]; ];
} }
function getSetting(){
return 'test@xshop.ir';
/**
* validate basic setting request b4 save
* @param $setting
* @param $newValue
* @return mixed|string
*/
function validateSettingRequest($setting, $newValue)
{
if (!$setting->is_basic) {
return $newValue;
}
switch ($setting->key) {
case 'optimize':
if ($newValue != 'jpg' || $newValue != 'webp') {
return 'webp';
}
case 'gallery_thumb':
case 'post_thumb':
case 'product_thumb':
case 'product_image':
$temp = explode('x', $newValue);
if (count($temp) != 2) {
return '500x500';
} else {
if ((int)$temp[0] < 50 || (int)$temp[1] < 50) {
return '500x500';
}
}
}
return $newValue;
}
/***
* get setting by key
* @param string $key setting key
* @return false|mixed|string|null
*/
function getSetting($key)
{
if (!isset($_SERVER['SERVER_NAME']) || !\Schema::hasTable('settings')) {
return false;
}
$x = Setting::where('key', $key)->first();
if ($x == null) {
// $a = new \stdClass();
return '';
}
if (config('app.xlang') && ($x->type == 'group' || $x->type == 'category')) {
$defLang = config('app.xlang_main');
return $x->getTranslations('value')[$defLang];
}
return $x->value;
}
function imageSizeConvertValidate($size){
$s = getSetting($size);
if ($s == null){
$t = explode('x',$size);
if (config('app.media'.$size) == null || config('app.media'.$size) == ''){
$t[0] = 500 ;
$t[1] = 500 ;
}
}else{
$t = explode('x',$s);
}
return $t;
} }

@ -0,0 +1,102 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\SettingSaveRequest;
use App\Models\Category;
use App\Models\Group;
use App\Models\Setting;
use Illuminate\Http\Request;
class SettingController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
$settings = Setting::where('active', 1)
->orderBy('section')->get(); //ESH// just active setting`s show
$cats = Category::all(['id','name']);
$groups = Group::all(['id','name']);
return view('admin.commons.setting',
compact('settings', 'cats','groups'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(SettingSaveRequest $request)
{
//
$set = new Setting();
$set->title = $request->title;
$set->key = $request->key;
$set->section = $request->section;
$set->type = $request->type;
$set->size = $request->size;
$set->save();
return redirect()->back()->with(['message' => __('Setting added to website')]);
}
/**
* Display the specified resource.
*/
public function show(Setting $setting)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Setting $setting)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request)
{
$all = $request->all();
foreach ($all as $key => $val) {
$set = Setting::where('key', $key)->first();
if ($set != null && !$request->hasFile($key)) {
$set->value = validateSettingRequest($set,$val);
$set->save();
}
}
$files = $request->allFiles();
if (isset($files['file'])) {
foreach ($files['file'] as $index => $file) {
if ($file->extension() == 'mp4' || $file->extension() == 'mp3'){
$file->move(public_path('upload/media/'), str_replace('_','.',$index) );//store('/images/'.,['disk' => 'public']);
}else{
$file->move(public_path('upload/images/'), str_replace('_','.',$index) );//store('/images/'.,['disk' => 'public']);
}
}
}
return redirect()->back()->with(['message' => __('Setting of website updated')]);
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Setting $setting)
{
//
}
}

@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SettingSaveRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return auth()->check() && auth()->user()->hasRole('developer');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'title' => ['required', 'string','min:3', 'max:255'],
'key' => ['required', 'string', 'alpha_dash', 'max:255', "unique:settings,key,".$this->id],
'type' => ['required', 'string'],
'section' => ['required', 'string', 'max:255', 'min:2'],
'size' => ['required','integer','min:1','max:12']
];
}
}

@ -4,6 +4,9 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Spatie\Image\Enums\AlignPosition;
use Spatie\Image\Enums\Fit;
use Spatie\Image\Enums\Unit;
use Spatie\MediaLibrary\Conversions\Manipulations; use Spatie\MediaLibrary\Conversions\Manipulations;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\InteractsWithMedia;
@ -25,20 +28,21 @@ class Gallery extends Model implements HasMedia
{ {
$this->addMediaConversion('gallery-image')->optimize(); $this->addMediaConversion('gallery-image')->optimize();
$t = explode('x',config('app.media.gallery_thumb')); $t = imageSizeConvertValidate('gallery_thumb');
if (config('starter-kit.gallery_thumb') == null || config('starter-kit.gallery_thumb') == ''){ $mc = $this->addMediaConversion('gthumb')->width($t[0])
$t[0] = 500 ;
$t[1] = 500 ;
}
$this->addMediaConversion('gthumb')->width($t[0])
->height($t[1]) ->height($t[1])
->nonQueued() ->nonQueued()
->crop( $t[0], $t[1])->optimize(); ->crop( $t[0], $t[1])
// ->watermark(public_path('images/logo.png'))->watermarkOpacity(50); ->optimize()
// ->withResponsiveImages(); ->format(getSetting('optimize'));
if (getSetting('watermark')){
$mc->watermark(public_path('upload/images/logo.png'),
AlignPosition::BottomLeft,5,5,Unit::Percent,
15,Unit::Percent,15,Unit::Percent,Fit::Contain,50);
}
// ->withResponsiveImages();
} }
public function getRouteKeyName() public function getRouteKeyName()

@ -4,6 +4,9 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Spatie\Image\Enums\AlignPosition;
use Spatie\Image\Enums\Fit;
use Spatie\Image\Enums\Unit;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media; use Spatie\MediaLibrary\MediaCollections\Models\Media;
@ -24,18 +27,23 @@ class Image extends Model implements HasMedia
public function registerMediaConversions(Media $media = null): void public function registerMediaConversions(Media $media = null): void
{ {
$t = explode('x', config('starter-kit.post_thumb')); $t = imageSizeConvertValidate('gallery_thumb');
if (config('starter-kit.gallery_thumb') == null || config('starter-kit.gallery_thumb') == '') {
$t[0] = 500;
$t[1] = 500;
}
$this->addMediaConversion('image-image')->optimize(); $this->addMediaConversion('image-image')->optimize();
$this->addMediaConversion('gthumb')->width($t[0]) $mc = $this->addMediaConversion('githumb')
->width($t[0])
->height($t[1]) ->height($t[1])
->nonQueued() ->nonQueued()
->crop( $t[0], $t[1])->optimize(); ->crop( $t[0], $t[1])
->optimize()
->format(getSetting('optimize'));
if (getSetting('watermark')){
$mc->watermark(public_path('upload/images/logo.png'),
AlignPosition::BottomLeft,5,5,Unit::Percent,
15,Unit::Percent,15,Unit::Percent,Fit::Contain,50);
}
// ->watermark(public_path('images/logo.png'))->watermarkOpacity(50); // ->watermark(public_path('images/logo.png'))->watermarkOpacity(50);
// ->withResponsiveImages(); // ->withResponsiveImages();
} }
@ -43,9 +51,9 @@ class Image extends Model implements HasMedia
public function imgurl() public function imgurl()
{ {
if ($this->getMedia()->count() > 0) { if ($this->getMedia()->count() > 0) {
return $this->getMedia()->first()->getUrl('gthumb'); return $this->getMedia()->first()->getUrl('githumb');
} else { } else {
return "no image"; return asset('assets/upload/logo.svg');
} }
} }
} }

@ -5,6 +5,9 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Image\Enums\AlignPosition;
use Spatie\Image\Enums\Fit;
use Spatie\Image\Enums\Unit;
use Spatie\MediaLibrary\MediaCollections\Models\Media; use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\InteractsWithMedia;
@ -38,19 +41,22 @@ class Post extends Model implements HasMedia
{ {
$t = explode('x', config('app.media.post_thumb')); $t = explode('x', config('app.media.post_thumb'));
if (config('app.media.post_thumb') == null || config('app.media.post_thumb') == '') { $t = imageSizeConvertValidate('post_thumb');
$t[0] = 500;
$t[1] = 500;
}
$this->addMediaConversion('post-image') $mc = $this->addMediaConversion('post-image')
->width($t[0]) ->width($t[0])
->height($t[1]) ->height($t[1])
->crop( $t[0], $t[1]) ->crop( $t[0], $t[1])
->optimize() ->optimize()
->sharpen(10) ->sharpen(10)
->nonQueued() ->nonQueued()
->format('webp'); ->format(getSetting('optimize'));
if (getSetting('watermark')){
$mc->watermark(public_path('upload/images/logo.png'),
AlignPosition::BottomLeft,5,5,Unit::Percent,
15,Unit::Percent,15,Unit::Percent,Fit::Contain,50);
}
} }

@ -6,6 +6,9 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Plank\Metable\Metable; use Plank\Metable\Metable;
use Spatie\Image\Enums\AlignPosition;
use Spatie\Image\Enums\Fit;
use Spatie\Image\Enums\Unit;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media; use Spatie\MediaLibrary\MediaCollections\Models\Media;
@ -49,37 +52,36 @@ class Product extends Model implements HasMedia
public function registerMediaConversions(?Media $media = null): void public function registerMediaConversions(?Media $media = null): void
{ {
$ti = explode('x', config('app.media.product_image')); $ti = imageSizeConvertValidate('product_image');
$t = imageSizeConvertValidate('product_thumb');
if (config('app.media.product_image') == null || config('app.media.product_image') == '') { $mc = $this->addMediaConversion('product-thumb')
$ti[0] = 1200;
$ti[1] = 1200;
}
$t = explode('x', config('app.media.product_thumb'));
if (config('app.media.product_thumb') == null || config('app.media.product_thumb') == '') {
$t[0] = 500;
$t[1] = 500;
}
$this->addMediaConversion('product-thumb')
->width($t[0]) ->width($t[0])
->height($t[1]) ->height($t[1])
->crop($t[0], $t[1]) ->crop($t[0], $t[1])
->optimize() ->optimize()
->sharpen(10) ->sharpen(10)
->nonQueued() ->nonQueued()
->format('webp'); ->format(getSetting('optimize'));
$this->addMediaConversion('product-image') $mc2 = $this->addMediaConversion('product-image')
->width($ti[0]) ->width($ti[0])
->height($ti[1]) ->height($ti[1])
->crop($ti[0], $ti[1]) ->crop($ti[0], $ti[1])
->optimize() ->optimize()
->sharpen(10) ->sharpen(10)
->nonQueued() ->nonQueued()
->format('webp'); ->format(getSetting('optimize'));
if (getSetting('watermark')){
$mc->watermark(public_path('upload/images/logo.png'),
AlignPosition::BottomLeft,5,5,Unit::Percent,
15,Unit::Percent,15,Unit::Percent,Fit::Contain,50);
$mc2->watermark(public_path('upload/images/logo.png'),
AlignPosition::BottomLeft,5,5,Unit::Percent,
15,Unit::Percent,15,Unit::Percent,Fit::Contain,50);
}
} }
@ -146,6 +148,13 @@ class Product extends Model implements HasMedia
} }
public function imgUrl(){ public function imgUrl(){
if ($this->getMedia()->count() > 0) {
return $this->getMedia()[$this->image_index]->getUrl('product-image');
} else {
return asset('assets/upload/logo.svg');
}
}
public function orginalImageUrl(){
if ($this->getMedia()->count() > 0) { if ($this->getMedia()->count() > 0) {
return $this->getMedia()[$this->image_index]->getUrl(); return $this->getMedia()[$this->image_index]->getUrl();
} else { } else {
@ -154,7 +163,7 @@ class Product extends Model implements HasMedia
} }
public function imgUrl2(){ public function imgUrl2(){
if ($this->getMedia()->count() > 0 && isset($this->getMedia()[1])) { if ($this->getMedia()->count() > 0 && isset($this->getMedia()[1])) {
return $this->getMedia()[1]->getUrl(); return $this->getMedia()[1]->getUrl('product-image');
} else { } else {
return asset('assets/upload/logo.svg'); return asset('assets/upload/logo.svg');
} }

@ -4,8 +4,14 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class Setting extends Model class Setting extends Model
{ {
use HasFactory; use HasFactory, HasTranslations;
public $translatable = ['value'];
public static $settingTypes = ['TEXT', 'LONGTEXT', 'CODE', 'EDITOR',
'CATEGORY', 'GROUP', 'CHECKBOX', 'FILE'];
} }

@ -14,11 +14,14 @@ return new class extends Migration
Schema::create('settings', function (Blueprint $table) { Schema::create('settings', function (Blueprint $table) {
$table->id(); $table->id();
$table->string('section'); $table->string('section');
$table->string('type'); $table->enum('type',\App\Models\Setting::$settingTypes);
$table->string('title'); $table->string('title');
$table->boolean('active')->default(true); $table->boolean('active')->default(true);
$table->string('key')->unique(); $table->string('key')->unique();
$table->text('value')->nullable(); $table->text('value')->nullable();
$table->boolean('ltr')->default(false);
$table->boolean('is_basic')->default(false);
$table->boolean('size')->default('12');
$table->timestamps(); $table->timestamps();
}); });
} }

@ -32,6 +32,7 @@ class DatabaseSeeder extends Seeder
PropSeeder::class, PropSeeder::class,
ProductSeeder::class, ProductSeeder::class,
CommentSeeder::class, CommentSeeder::class,
SettingSeeder::class,
] ]
); );
} }

@ -2,6 +2,7 @@
namespace Database\Seeders; namespace Database\Seeders;
use App\Models\Setting;
use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
@ -13,5 +14,174 @@ class SettingSeeder extends Seeder
public function run(): void public function run(): void
{ {
// //
$sections = [
'General' => [
[
'title' => __("Email"),
'key' => 'email',
'type' => 'TEXT',
'ltr' => true,
'value' => 'xshop@xstack.ir',
'size' => '6',
],
[
'title' => __("Tel"),
'key' => 'tel',
'type' => 'TEXT',
'ltr' => true,
'value' => '+98-21-9988-7766',
'size' => '6',
],
[
'title' => __("Subtitle"),
'key' => 'subtitle',
'type' => 'TEXT',
'value' => 'another shop with xShop',
],
[
'title' => __("copyright"),
'key' => 'copyright',
'type' => 'TEXT',
'value' => 'xShop community © ' . date('Y'),
],
[
'title' => __("Twitter (x)"),
'key' => 'tw',
'type' => 'TEXT',
'size' => '4',
],
[
'title' => __("Facebook"),
'key' => 'fb',
'type' => 'TEXT',
'size' => '4',
],
[
'title' => __("Instagram"),
'key' => 'in',
'type' => 'TEXT',
'size' => '4',
],
[
'title' => __("LinkedIn"),
'key' => 'li',
'type' => 'TEXT',
'size' => '4',
],
[
'title' => __("Youtube"),
'key' => 'yt',
'type' => 'TEXT',
'size' => '4',
],
[
'title' => __("Telegram"),
'key' => 'tg',
'type' => 'TEXT',
'size' => '4',
],
[
'title' => __('Under construction'),
'key' => 'under',
'type' => 'CHECKBOX',
'value' => 0,
],
],
'SEO' => [
[
'title' => __("Common keyword"),
'key' => 'keyword',
'type' => 'TEXT',
'value' => 'shop,xshop, sale, xStack',
],
[
'title' => __("Common description"),
'key' => 'desc',
'type' => 'TEXT',
'value' => 'Best customizable shop in the world',
],
[
'title' => __("Google Webmaster code"),
'key' => 'google-webmaster-code',
'type' => 'CODE',
],
[
'title' => __("SEO image"),
'key' => 'site_image',
'type' => 'FILE',
],
],
'Media' => [
[
'title' => __("Logo (svg)"),
'key' => 'logo_svg',
'type' => 'FILE',
],
[
'title' => __("Logo (png)"),
'key' => 'logo_png',
'type' => 'FILE',
],
[
'title' => __('Optimize type'),
'key' => 'optimize',
'type' => 'TEXT',
'value' => 'webp',
'size' => '6',
],
[
'title' => __('Watermark'),
'key' => 'watermark',
'type' => 'CHECKBOX',
'value' => false,
'size' => '6',
],
[
'title' => __('Product thumbnail size'),
'key' => 'product_image',
'type' => 'TEXT',
'value' => '1200x1200',
'size' => '6',
],
[
'title' => __('Product image size'),
'key' => 'product_thumb',
'type' => 'TEXT',
'value' => '500x500',
'size' => '6',
],
[
'title' => __('Post thumbnail size'),
'key' => 'post_thumb',
'type' => 'TEXT',
'value' => '500x500',
'size' => '6',
],
[
'title' => __('Gallery thumbnail size'),
'key' => 'gallery_thumb',
'type' => 'TEXT',
'value' => '500x500',
'size' => '6',
],
]
];
foreach ($sections as $section => $section_data) {
foreach ($section_data as $set) {
$setting = new Setting();
$setting->title = $set['title'];
$setting->section = $section;
$setting->key = $set['key'];
$setting->value = $set['value']??null;
$setting->type = $set['type']??'TEXT';
$setting->ltr = $set['ltr']??false;
$setting->is_basic = true;
$setting->size = $set['size']??12;;
$setting->save();
}
}
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

@ -24,6 +24,7 @@ import './panel/general-events.js';
import './panel/editor-handle.js'; import './panel/editor-handle.js';
import './panel/step-controller.js'; import './panel/step-controller.js';
import './panel/product-upload-controller.js'; import './panel/product-upload-controller.js';
import './panel/setting-section-controller.js';
/** /**
* Next, we will create a fresh Vue application instance. You may then begin * Next, we will create a fresh Vue application instance. You may then begin

@ -0,0 +1,59 @@
document.addEventListener('DOMContentLoaded', function () {
// Get all section group items
let sectionGroupItems = document.querySelectorAll('.section-group-item');
// Get all sections
let sections = document.querySelectorAll('#setting-sections section');
// Hide all sections initially
sections?.forEach(section => {
section.style.display = 'none';
});
// Show/hide sections on click
sectionGroupItems?.forEach(item => {
item.addEventListener('click', function (event) {
try {
event.preventDefault();
let targetId = this.getAttribute('href').slice(1);
sections.forEach(section => {
if (section.id === targetId) {
section.style.display = 'block';
} else {
section.style.display = 'none';
}
});
sectionGroupItems.forEach(link => {
link.classList.remove('active');
});
this.classList.add('active');
} catch (e) {
console.log(e.message);
}
});
});
// Show section based on hash in URL
let hash = window.location.hash.slice(1);
if (hash) {
sections.forEach(section => {
if (section.id === hash) {
section.style.display = 'block';
} else {
section.style.display = 'none';
}
});
}
try {
// Show the first section on page load
document.querySelector('.section-group-item').dispatchEvent(new Event('click'));
} catch (e) {
}
});

@ -128,3 +128,33 @@ a.btn,a.action-btn,a.circle-btn{
z-index: 1; z-index: 1;
margin-bottom: -75px; margin-bottom: -75px;
} }
.section-group{
.section-group-item{
display: block;
padding: .5rem;
background: #ffffff11;
border-bottom: 1px solid #00000022;
color: white;
&.active{
background: $primary-color-panel;
}
&:hover{
background: rgba($primary-color-panel,.7);
}
}
}
#setting-sections{
section{
display: none;
background: $lighter-color;
padding: 1rem;
.setting-field{
padding: 5px;
}
}
}

@ -21,7 +21,7 @@
<li> <li>
{{__("If you want to only attach to other staff members and do not want to appear in the website attachment list, uncheck `fillable`")}} {{__("If you want to only attach to other staff members and do not want to appear in the website attachment list, uncheck `fillable`")}}
</li> </li>
@if($item->file == null) @if(isset($item) && $item->file == null)
<li> <li>
{{__("There is noting file to show!")}} {{__("There is noting file to show!")}}
</li> </li>
@ -32,7 +32,7 @@
</ul> </ul>
</div> </div>
@if($item) @if(isset($item))
<div class="item-list mb-3"> <div class="item-list mb-3">
<h3 class="p-3"> <h3 class="p-3">
<i class="ri-file-info-line"></i> <i class="ri-file-info-line"></i>

@ -0,0 +1,139 @@
@extends('layouts.app')
@section('title')
{{__("Setting")}} -
@endsection
@section('content')
<div class="row">
<div class="mb-5 pb-5">
<div class="row">
{{-- list side bar start--}}
<div class="col-xl-3">
@include('components.err')
<div class="item-list mb-3">
<h3 class="p-3">
<i class="ri-message-3-line"></i>
{{__("Tips")}}
</h3>
<ul>
<li>
{{__("Recommends")}}
</li>
</ul>
</div>
<div class="item-list mb-3">
<h3 class="p-3">
<i class="ri-file-2-line"></i>
{{__("Sections")}}
</h3>
<div class="p-2">
<div class="section-group">
@foreach(\App\Models\Setting::groupBy('section')->pluck('section')->toArray() as $sec)
<a href="#{{$sec}}" class="section-group-item">
{{$sec}}
</a>
@endforeach
</div>
</div>
</div>
<div class="item-list mb-3">
<h3 class="p-3">
<i class="ri-add-line"></i>
{{__("Add new setting")}}
</h3>
@if(auth()->user()->hasRole('developer'))
<form class="p-2 m-3 mt-0" method="post" action="{{route('admin.setting.store')}}">
@csrf
<div class="form-group">
<label for="section">
{{__('Section')}}
</label>
<input name="section" type="text"
class="form-control @error('section') is-invalid @enderror"
placeholder="{{__('Section')}}"
value="{{old('section',$setting->section??null)}}"/>
</div>
<div class="form-group">
<label for="type">
{{__('Type')}}
</label>
<select name="type" id="type"
class="form-control @error('type') is-invalid @enderror">
@foreach(\App\Models\Setting::$settingTypes as $type)
<option value="text"
@if (old('type') == $type ) selected @endif >{{__($type)}} </option>
@endforeach
</select>
</div>
<div class="form-group">
<label for="title">
{{__('Title')}}
</label>
<input name="title" type="text"
class="form-control @error('title') is-invalid @enderror"
placeholder="{{__('Title')}}"
value="{{old('title')}}"/>
</div>
<div class="form-group">
<label for="key">
{{__('Key')}}
</label>
<input name="key" type="text"
class="form-control @error('key') is-invalid @enderror"
placeholder="{{__('Key')}}" value="{{old('key')}}"/>
</div>
<div class="form-group">
<label for="size">
{{__('Size')}}
</label>
<input name="size" type="number"
class="form-control @error('size') is-invalid @enderror"
placeholder="{{__('Size')}}" value="{{old('size',12)}}"/>
</div>
<label> &nbsp;</label>
<input name="" type="submit" class="btn w-100 btn-primary mt-2"
value="{{__('Add to setting')}}"/>
</form>
@endif
</div>
</div>
<div class="col-xl-9 ps-xl-0" id="setting-sections">
<form action="{{route('admin.setting.update')}}" method="post" enctype="multipart/form-data">
@csrf
@foreach(\App\Models\Setting::groupBy('section')->pluck('section')->toArray() as $sec)
<section id="{{$sec}}">
<div class="row">
@foreach($settings as $setting)
@if($setting->section == $sec)
@include('components.setting-field')
@endif
@endforeach
</div>
</section>
@endforeach
<button class="action-btn circle-btn"
data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-custom-class="custom-tooltip"
data-bs-title="{{__("Add another one")}}"
href="{{getRoute('create')}}"
>
<i class="ri-save-2-line"></i>
</button>
</form>
</div>
<div class="mb-5">
&nbsp;
</div>
</div>
</div>
@endsection

@ -17,7 +17,7 @@
@foreach($item->getMedia() as $k => $media) @foreach($item->getMedia() as $k => $media)
<div data-id="-1" data-key="{{$k}}" <div data-id="-1" data-key="{{$k}}"
class="image-index col-xl-3 col-md-4 border p-3 @if($k == $item->image_index) indexed @endif"> class="image-index col-xl-3 col-md-4 border p-3 @if($k == $item->image_index) indexed @endif">
<img class="img-list" src="{{$media->getUrl()}}" alt="{{$k}}"> <img class="img-list" src="{{$media->getUrl('product-image')}}" alt="{{$k}}">
<div class="btn btn-danger upload-remove-image d-block"> <div class="btn btn-danger upload-remove-image d-block">
<span class="ri-close-line"></span> <span class="ri-close-line"></span>
</div> </div>

@ -216,7 +216,7 @@
</li> </li>
<li data-bs-toggle="tooltip" data-bs-placement="auto" data-bs-custom-class="custom-tooltip" <li data-bs-toggle="tooltip" data-bs-placement="auto" data-bs-custom-class="custom-tooltip"
data-bs-title="{{__("Setting")}}"> data-bs-title="{{__("Setting")}}">
<a href=""> <a href="{{route('admin.setting.index')}}">
<i class="ri-settings-4-line"></i> <i class="ri-settings-4-line"></i>
</a> </a>
</li> </li>

@ -0,0 +1,102 @@
<div class="setting-field col-md-{{$setting->size}}">
<label for="{{$setting->key}}">
{{$setting->title}}
{{-- // WIP translate--}}
</label>
@switch($setting->type)
@case('LONGTEXT')
<textarea name="{{$setting->key}}" @if($setting->ltr) dir="ltr" @endif id="{{$setting->key}}"
class="form-control"
rows="5">{{old($setting->key, $setting->value)}}</textarea>
@break
@case('CODE')
<textarea dir="ltr" name="{{$setting->key}}" id="{{$setting->key}}"
class="form-control"
rows="5">{{old($setting->key, $setting->value)}}</textarea>
@break
@case('EDITOR')
<textarea name="{{$setting->key}}" id="{{$setting->key}}"
class="form-control ckeditorx"
rows="5">{{old($setting->key, $setting->value)}}</textarea>
@break
@case('CHECKBOX')
<select name="{{$setting->key}}" id="{{$setting->key}}"
class="form-control @error('status') is-invalid @enderror">
<option value="1"
@if (old($setting->key, $setting->value??0) == '1' ) selected @endif >{{__("True")}} </option>
<option value="0"
@if (old($setting->key, $setting->value??0) == '0' ) selected @endif >{{__("False")}} </option>
</select>
@break
@case('CATEGORY')
<searchable-select
@error('category_id') :err="true" @enderror
:items='@json($cats)'
title-field="name"
value-field="id"
xlang="{{config('app.locale')}}"
xid="{{$setting->key}}"
xname="{{$setting->key}}"
@error('category_id') :err="true" @enderror
xvalue='{{old($setting->key,$setting->value??null)}}'
:close-on-Select="true"></searchable-select>
@break
@case('GROUP')
<searchable-select
@error('category_id') :err="true" @enderror
:items='@json($groups)'
title-field="name"
value-field="id"
xlang="{{config('app.locale')}}"
xid="{{$setting->key}}"
xname="{{$setting->key}}"
@error('category_id') :err="true" @enderror
xvalue='{{old($setting->key,$setting->value??null)}}'
:close-on-Select="true"></searchable-select>
@break
@case('FILE')
<div class="row">
@php($ext = strtolower(pathinfo(str_replace('_','.',$setting->key), PATHINFO_EXTENSION)))
<div class="col-md-5 ">
<input type="file" accept=".{{pathinfo(str_replace('_','.',$setting->key), PATHINFO_EXTENSION)}}" class="form-control" name="file[{{$setting->key}}]" id="{{$setting->key}}">
</div>
@if(!in_array($ext, ['svg','jpg','png','gif','webp'] ) )
<div class="col-md-2">
<a class="btn btn-primary w-100" href="{{asset('upload/file/'.str_replace('_','.',$setting->key))}}?{{time()}}">
<i class="ri-download-2-line"></i>
</a>
</div>
@endif
<div class="col-md-5">
@if($ext == 'mp4')
<video controls src="{{asset('upload/file/'.str_replace('_','.',$setting->key))}}?{{time()}}" class="img-fluid" style="max-height: 150px;max-width: 45%" ></video>
<br>
@elseif($ext == 'mp3')
<audio controls src="{{asset('upload/file/'.str_replace('_','.',$setting->key))}}?{{time()}}" class="img-fluid" style="max-height: 150px;max-width: 45%" ></audio>
<br>
@elseif(in_array($ext, ['svg','jpg','png','gif','webp'] ) )
<img src="{{asset('upload/images/'.str_replace('_','.',$setting->key))}}?{{time()}}"
class="img-fluid" style="max-height: 150px;max-width: 45%" alt="{{$setting->key}}">
@endif
</div>
</div>
@break
@default
@if($setting->key == 'optimize')
<select class="form-control" name="{{$setting->key}}" id="{{$setting->key}}">
<option value="1"
@if (old($setting->key, $setting->value??'webp') == 'jpg' ) selected @endif >{{__("jpg")}} </option>
<option value="0"
@if (old($setting->key, $setting->value??'webp') == 'webp' ) selected @endif >{{__("webp")}} </option>
</select>
@else
<input type="text" id="{{$setting->key}}"
name="{{$setting->key}}" class="form-control"
value="{{old($setting->key, $setting->value)}}" @if($setting->ltr) dir="ltr" @endif>
@endif
@endswitch
</div>

@ -254,6 +254,15 @@ Route::prefix(config('app.panel.prefix'))->name('admin.')->group(
Route::post('update/{item}', [\App\Http\Controllers\Admin\AddressController::class, 'update'])->name('update'); Route::post('update/{item}', [\App\Http\Controllers\Admin\AddressController::class, 'update'])->name('update');
Route::get('destroy/{item}', [\App\Http\Controllers\Admin\AddressController::class, 'destroy'])->name('destroy'); Route::get('destroy/{item}', [\App\Http\Controllers\Admin\AddressController::class, 'destroy'])->name('destroy');
}); });
Route::prefix('setting')->name('setting.')->group(
function () {
Route::get('index', [\App\Http\Controllers\Admin\SettingController::class, "index"])->name('index');
Route::post('store', [\App\Http\Controllers\Admin\SettingController::class, "store"])->name('store');
Route::post('update', [\App\Http\Controllers\Admin\SettingController::class, "update"])->name('update');
}
);
}); });
}); });

Loading…
Cancel
Save