first upload all files

This commit is contained in:
NW
2023-06-11 13:14:03 +01:00
parent f14dbc52b5
commit c08b36d1b6
1705 changed files with 106852 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
<?php
namespace Modules\Slider\Admin;
use Modules\Admin\Ui\Tab;
use Modules\Admin\Ui\Tabs;
class SliderTabs extends Tabs
{
/**
* Indicate that submit button should add offset class.
*
* @var bool
*/
protected $buttonOffset = false;
/**
* Make new tabs with groups.
*
* @return void
*/
public function make()
{
$this->group('slider_information', trans('slider::sliders.tabs.group.slider_information'))
->active()
->add($this->slides())
->add($this->settings());
}
private function slides()
{
return tap(new Tab('slides', trans('slider::sliders.tabs.slides')), function (Tab $tab) {
$tab->active();
$tab->weight(5);
$tab->view('slider::admin.sliders.tabs.slides');
});
}
private function settings()
{
return tap(new Tab('settings', trans('slider::sliders.tabs.settings')), function (Tab $tab) {
$tab->weight(10);
$tab->fields(['name']);
$tab->view('slider::admin.sliders.tabs.settings');
});
}
}

View File

@@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Define which assets will be available through the asset manager
|--------------------------------------------------------------------------
| These assets are registered on the asset manager
*/
'all_assets' => [
'admin.slider.css' => ['module' => 'slider:admin/css/slider.css'],
'admin.slider.js' => ['module' => 'slider:admin/js/slider.js'],
],
/*
|--------------------------------------------------------------------------
| Define which default assets will always be included in your pages
| through the asset pipeline
|--------------------------------------------------------------------------
*/
'required_assets' => [],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'admin.sliders' => [
'index' => 'slider::permissions.index',
'create' => 'slider::permissions.create',
'edit' => 'slider::permissions.edit',
'destroy' => 'slider::permissions.destroy',
],
];

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSlidersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sliders', function (Blueprint $table) {
$table->increments('id');
$table->boolean('autoplay')->nullable();
$table->integer('autoplay_speed')->nullable();
$table->boolean('dots')->nullable();
$table->boolean('arrows')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('sliders');
}
}

View File

@@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSliderTranslationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('slider_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('slider_id')->unsigned();
$table->string('locale');
$table->string('name');
$table->unique(['slider_id', 'locale']);
$table->foreign('slider_id')->references('id')->on('sliders')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('slider_translations');
}
}

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSliderSlidesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('slider_slides', function (Blueprint $table) {
$table->increments('id');
$table->integer('slider_id')->unsigned();
$table->integer('file_id')->nullable()->unsigned();
$table->text('options')->nullable();
$table->string('call_to_action_url')->nullable();
$table->boolean('open_in_new_window')->nullable();
$table->timestamps();
$table->foreign('slider_id')->references('id')->on('sliders')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('slider_slides');
}
}

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSliderSlideTranslationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('slider_slide_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('slider_slide_id')->unsigned();
$table->string('locale');
$table->string('caption_1')->nullable();
$table->string('caption_2')->nullable();
$table->string('call_to_action_text')->nullable();
$table->unique(['slider_slide_id', 'locale']);
$table->foreign('slider_slide_id')->references('id')->on('slider_slides')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('slider_slide_translations');
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddPositionToSliderSlidesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('slider_slides', function (Blueprint $table) {
$table->integer('position')->after('open_in_new_window')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('slider_slides', function (Blueprint $table) {
$table->dropColumn('position');
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveFileIdFromSliderSlidesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('slider_slides', function (Blueprint $table) {
$table->dropColumn('file_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('slider_slides', function (Blueprint $table) {
$table->integer('file_id')->nullable()->unsigned();
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddFileIdToSliderSlideTranslationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('slider_slide_translations', function (Blueprint $table) {
$table->integer('file_id')->after('locale')->nullable()->unsigned();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('slider_slide_translations', function (Blueprint $table) {
$table->dropColumn('file_id');
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddDirectionColumnToSliderSlideTranslationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('slider_slide_translations', function (Blueprint $table) {
$table->string('direction')->nullable()->before('call_to_action_text');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('slider_slide_translations', function (Blueprint $table) {
$table->dropColumn('direction');
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddSpeedColumnToSlidersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('sliders', function (Blueprint $table) {
$table->integer('speed')->nullable()->after('id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('sliders', function (Blueprint $table) {
$table->dropColumn('speed');
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddFadeColumnToSlidersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('sliders', function (Blueprint $table) {
$table->boolean('fade')->default(false)->after('autoplay_speed');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('sliders', function (Blueprint $table) {
$table->dropColumn('fade');
});
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace Modules\Slider\Entities;
use Modules\Admin\Ui\AdminTable;
use Illuminate\Support\Facades\Cache;
use Illuminate\Database\Eloquent\Model;
use Modules\Support\Eloquent\Translatable;
class Slider extends Model
{
use Translatable;
/**
* The relations to eager load on every query.
*
* @var array
*/
protected $with = ['translations', 'slides'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['speed', 'autoplay', 'autoplay_speed', 'fade', 'dots', 'arrows'];
/**
* The attributes that are translatable.
*
* @var array
*/
public $translatedAttributes = ['name'];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted()
{
static::saved(function ($slider) {
$slider->saveSlides(request('slides', []));
$slider->clearCache();
});
}
public function shouldAutoPlay()
{
return $this->autoplay ? 'true' : 'false';
}
public function clearCache()
{
Cache::tags("sliders.{$this->id}")->flush();
}
public static function findWithSlides($id)
{
if (is_null($id)) {
return;
}
return Cache::tags("sliders.{$id}")
->rememberForever(md5("sliders.{$id}:" . locale()), function () use ($id) {
return static::with('slides')->find($id);
});
}
public function slides()
{
return $this->hasMany(SliderSlide::class)->orderBy('position');
}
public function getAutoplaySpeedAttribute($autoplaySpeed)
{
return $autoplaySpeed ?: 3000;
}
public function table()
{
return new AdminTable($this->newQuery());
}
/**
* Save slides for the slider.
*
* @param array $slides
* @return void
*/
public function saveSlides($slides)
{
$ids = $this->getDeleteCandidates($slides);
if ($ids->isNotEmpty()) {
$this->slides()->whereIn('id', $ids)->delete();
}
foreach (array_reset_index($slides) as $index => $slide) {
$this->slides()->updateOrCreate(
['id' => $slide['id']],
$slide + ['position' => $index]
);
}
}
private function getDeleteCandidates($slides = [])
{
return $this->slides()
->pluck('id')
->diff(array_pluck($slides, 'id'));
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace Modules\Slider\Entities;
use Modules\Media\Entities\File;
use Modules\Support\Eloquent\Model;
use Modules\Support\Eloquent\Translatable;
class SliderSlide extends Model
{
use Translatable;
/**
* The relations to eager load on every query.
*
* @var array
*/
protected $with = ['translations', 'file'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['options', 'call_to_action_url', 'open_in_new_window', 'position'];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'options' => 'array',
'open_in_new_window' => 'boolean',
];
/**
* The attributes that are translatable.
*
* @var array
*/
public $translatedAttributes = [
'file_id',
'caption_1',
'caption_2',
'direction',
'call_to_action_text',
];
public function isAlignedLeft()
{
return $this->direction === 'left';
}
public function isAlignedRight()
{
return $this->direction === 'right';
}
public function file()
{
return $this->belongsTo(File::class)->withDefault();
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Modules\Slider\Entities;
use Modules\Support\Eloquent\TranslationModel;
class SliderSlideTranslation extends TranslationModel
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'file_id',
'caption_1',
'caption_2',
'direction',
'call_to_action_text',
];
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Modules\Slider\Entities;
use Modules\Support\Eloquent\TranslationModel;
class SliderTranslation extends TranslationModel
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name'];
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Modules\Slider\Http\Controllers\Admin;
use Modules\Slider\Entities\Slider;
use Modules\Admin\Traits\HasCrudActions;
use Modules\Slider\Http\Requests\SaveSliderRequest;
class SliderController
{
use HasCrudActions;
/**
* Model for the resource.
*
* @var string
*/
protected $model = Slider::class;
/**
* Label of the resource.
*
* @var string
*/
protected $label = 'slider::sliders.slider';
/**
* View path of the resource.
*
* @var string
*/
protected $viewPath = 'slider::admin.sliders';
/**
* Form requests for the resource.
*
* @var array
*/
protected $validation = SaveSliderRequest::class;
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Modules\Slider\Http\Controllers\Admin;
use Modules\Admin\Traits\HasCrudActions;
use Modules\Slider\Entities\SliderOption;
use Modules\Slider\Http\Requests\SaveSliderOptionRequest;
class SliderOptionController
{
use HasCrudActions;
/**
* Model for the resource.
*
* @var string
*/
protected $model = SliderOption::class;
/**
* Label of the resource.
*
* @var string
*/
protected $label = 'slider::slider_options.slider_option';
/**
* View path of the resource.
*
* @var string
*/
protected $viewPath = 'slider::admin.slider_options';
/**
* Form requests for the resource.
*
* @var array
*/
protected $validation = SaveSliderOptionRequest::class;
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Modules\Slider\Http\Requests;
use Modules\Core\Http\Requests\Request;
class SaveSliderOptionRequest extends Request
{
/**
* Available attributes.
*
* @var string
*/
protected $moduleAttributes = 'slider::attributes';
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required',
];
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Modules\Slider\Http\Requests;
use Modules\Core\Http\Requests\Request;
class SaveSliderRequest extends Request
{
/**
* Available attributes.
*
* @var string
*/
protected $availableAttributes = 'slider::attributes';
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required',
];
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\Slider\Providers;
use Modules\Slider\Admin\SliderTabs;
use Modules\Support\Traits\AddsAsset;
use Illuminate\Support\ServiceProvider;
use Modules\Admin\Ui\Facades\TabManager;
class SliderServiceProvider extends ServiceProvider
{
use AddsAsset;
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
TabManager::register('sliders', SliderTabs::class);
$this->addAdminAssets('admin.sliders.(create|edit)', ['admin.media.js', 'admin.slider.css', 'admin.slider.js']);
}
}

View File

@@ -0,0 +1,41 @@
export default class {
constructor(data) {
this.slidePanelHtml = this.getSlidePanelHtml(data);
}
getSlidePanelHtml(data) {
data.slide.options = data.slide.options || this.getDefaultOptions();
let template = _.template($('#slide-template').html());
return $(template(data));
}
getDefaultOptions() {
return { caption_1: {}, caption_2: {}, direction: 'left', call_to_action: {} };
}
render() {
this.attachEventListeners();
this.showSelectedOptionBlock();
return this.slidePanelHtml;
}
attachEventListeners() {
this.slidePanelHtml.find('.delete-slide').on('click', () => {
this.slidePanelHtml.remove();
});
this.slidePanelHtml.find('.change-option-block').on('change', (e) => {
this.slidePanelHtml.find('.slide-options').hide();
this.slidePanelHtml.find(`.${e.currentTarget.value}`).show();
});
}
showSelectedOptionBlock() {
setTimeout(() => {
this.slidePanelHtml.find('.change-option-block').trigger('change');
});
}
}

View File

@@ -0,0 +1,58 @@
import Slide from './Slide';
export default class {
constructor() {
this.slideCount = 0;
this.addSlides(FleetCart.data['slider.slides']);
if (this.slideCount === 0) {
this.addSlide();
}
this.attachEventListeners();
this.makeSlidesSortable();
}
addSlides(slides) {
for (let attributes of slides) {
this.addSlide(attributes);
}
}
addSlide(attributes = {}) {
let slide = new Slide({ slideNumber: this.slideCount++, slide: attributes });
$('#slides-wrapper').append(slide.render());
}
attachEventListeners() {
$('.add-slide').on('click', () => {
this.addSlide();
});
this.attachImagePickerEventListener();
}
attachImagePickerEventListener() {
$('#slides-wrapper').on('click', '.slide-image', (e) => {
let picker = new MediaPicker({ type: 'image' });
picker.on('select', (file) => {
let html = `
<img src="${file.path}">
<input type="hidden" name="slides[${e.currentTarget.dataset.slideNumber}][file_id]" value="${file.id}">
`;
$(e.currentTarget).html(html);
});
});
}
makeSlidesSortable() {
Sortable.create(document.getElementById('slides-wrapper'), {
handle: '.slide-drag',
animation: 150,
});
}
}

View File

@@ -0,0 +1,9 @@
import Slider from './Slider';
new Slider();
$('#autoplay').on('change', (e) => {
$('.autoplay-speed-field').toggleClass('hide');
});
window.admin.removeSubmitButtonOffsetOn('#slides');

View File

@@ -0,0 +1,147 @@
.slide {
border: 1px solid #e9e9e9;
border-radius: 3px;
margin-bottom: 15px;
.slide-header {
padding: 15px;
background: #f6f6f7;
border-bottom: 1px solid #e9e9e9;
.slide-drag {
font-size: 16px;
color: #737881;
cursor: move;
margin: 3px 10px 0 0;
white-space: nowrap;
display: inline-block;
i {
float: left;
&:nth-child(2) {
margin-left: 1px;
}
}
}
span {
font-size: 16px;
}
.btn {
padding: 0;
background: transparent;
}
}
.slide-body {
position: relative;
padding: 15px;
.slide-tabs {
margin-left: 170px;
.nav-tabs {
display: inline-block;
margin: 0;
border: none;
a[data-toggle=tab] {
outline: none;
}
}
.tab-content {
border-top: 1px solid #d2d6de;
margin-top: -7px;
-webkit-margin-before: -6px;
padding-top: 15px;
}
.checkbox {
margin-top: 30px;
}
}
}
.slide-image {
position: absolute;
top: 30px;
left: 15px;
border: 1px solid #d2d6de;
border-radius: 3px;
height: 150px;
width: 150px;
cursor: pointer;
z-index: 0;
> img {
position: absolute;
left: 50%;
top: 50%;
max-height: 100%;
max-width: 100%;
z-index: 1;
transform: translate(-50%, -50%);
}
> i {
position: absolute;
left: 50%;
top: 50%;
font-size: 70px;
color: #d9d9d9;
transform: translate(-50%, -50%);
z-index: -1;
}
}
.slide-options {
display: none;
.form-horizontal {
border-top: 1px solid #d2d6de;
padding-top: 15px;
}
h4 {
margin: 6px 0 20px;
}
}
.form-group {
margin-left: 0;
margin-right: 0;
}
}
@media screen and (max-width: 767px) {
.slide {
.slide-image {
position: relative;
left: auto;
top: auto;
margin: 15px auto 30px;
display: table;
}
.slide-body .slide-tabs {
margin: 0;
clear: both;
}
.slide-options .form-horizontal {
clear: both;
margin-top: 15px;
}
}
}
@media screen and (max-width: 1199px) {
.slide {
.slide-body .slide-tabs .checkbox {
margin-top: 0;
}
}
}

View File

@@ -0,0 +1,23 @@
<?php
return [
'caption_1' => 'Caption 1',
'caption_2' => 'Caption 2',
'direction' => 'Direction',
'call_to_action_text' => 'Call to Action Text',
'call_to_action_url' => 'Call to Action URL',
'open_in_new_window' => 'Open in new window',
'caption_1_delay' => 'Delay',
'caption_1_effect' => 'Effect',
'caption_2_delay' => 'Delay',
'caption_2_effect' => 'Effect',
'call_to_action_delay' => 'Delay',
'call_to_action_effect' => 'Effect',
'name' => 'Name',
'speed' => 'Speed',
'autoplay' => 'Autoplay',
'autoplay_speed' => 'Autoplay Speed',
'fade' => 'Fade',
'dots' => 'Dots',
'arrows' => 'Arrows',
];

View File

@@ -0,0 +1,8 @@
<?php
return [
'index' => 'Index Slider',
'create' => 'Create Slider',
'edit' => 'Edit Slider',
'destroy' => 'Delete Slider',
];

View File

@@ -0,0 +1,58 @@
<?php
return [
'slider' => 'Slider',
'sliders' => 'Sliders',
'table' => [
'name' => 'Name',
],
'tabs' => [
'group' => [
'slider_information' => 'Slider Information',
],
'slides' => 'Slides',
'settings' => 'Settings',
],
'slide' => [
'add_slide' => 'Add Slide',
'image_slide' => 'Image Slide',
'form' => [
'tabs' => [
'general' => 'General',
'options' => 'Options',
],
'directions' => [
'left' => 'Left',
'right' => 'Right',
],
'caption_1' => 'Caption 1',
'caption_2' => 'Caption 2',
'call_to_action' => 'Call to Action',
'call_to_action_url' => 'Call to Action URL',
'open_in_new_window' => 'Open in new window',
'0s' => '0s',
'0_3s' => '0.3s',
'0_7s' => '0.7s',
],
],
'effects' => [
'fadeInUp' => 'fadeInUp',
'fadeInDown' => 'fadeInDown',
'fadeInLeft' => 'fadeInLeft',
'fadeInRight' => 'fadeInRight',
'lightSpeedIn' => 'lightSpeedIn',
'slideInUp' => 'slideInUp',
'slideInDown' => 'slideInDown',
'slideInLeft' => 'slideInLeft',
'slideInRight' => 'slideInRight',
'zoomIn' => 'zoomIn',
],
'form' => [
'enable_autoplay' => 'Enable autoplay',
'300ms' => '300ms',
'3000ms' => '3000ms',
'use_fade_instead_of_slide' => 'Fade slides instead of sliding',
'show_dots' => 'Show slider dots',
'show_arrows' => 'Show Prev/Next arrows',
],
];

View File

@@ -0,0 +1,18 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('admin::resource.create', ['resource' => trans('slider::sliders.slider')]))
<li><a href="{{ route('admin.sliders.index') }}">{{ trans('slider::sliders.sliders') }}</a></li>
<li class="active">{{ trans('admin::resource.create', ['resource' => trans('slider::sliders.slider')]) }}</li>
@endcomponent
@section('content')
<form method="POST" action="{{ route('admin.sliders.store') }}" class="form-horizontal" id="slider-create-form" novalidate>
{{ csrf_field() }}
{!! $tabs->render(compact('slider')) !!}
</form>
@endsection
@include('slider::admin.sliders.partials.shortcuts')

View File

@@ -0,0 +1,20 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('admin::resource.edit', ['resource' => trans('slider::sliders.slider')]))
@slot('subtitle', $slider->name)
<li><a href="{{ route('admin.sliders.index') }}">{{ trans('slider::sliders.sliders') }}</a></li>
<li class="active">{{ trans('admin::resource.edit', ['resource' => trans('slider::sliders.slider')]) }}</li>
@endcomponent
@section('content')
<form method="POST" action="{{ route('admin.sliders.update', $slider) }}" class="form-horizontal" id="slider-edit-form" novalidate>
{{ csrf_field() }}
{{ method_field('put') }}
{!! $tabs->render(compact('slider')) !!}
</form>
@endsection
@include('slider::admin.sliders.partials.shortcuts')

View File

@@ -0,0 +1,36 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('slider::sliders.sliders'))
<li class="active">{{ trans('slider::sliders.sliders') }}</li>
@endcomponent
@component('admin::components.page.index_table')
@slot('buttons', ['create'])
@slot('resource', 'sliders')
@slot('name', trans('slider::sliders.slider'))
@component('admin::components.table')
@slot('thead')
<tr>
@include('admin::partials.table.select_all')
<th>{{ trans('slider::sliders.table.name') }}</th>
<th data-sort>{{ trans('admin::admin.table.created') }}</th>
</tr>
@endslot
@endcomponent
@endcomponent
@push('scripts')
<script>
new DataTable('#sliders-table .table', {
columns: [
{ data: 'checkbox', orderable: false, searchable: false, width: '3%' },
{ data: 'name', name: 'translations.name', orderable: false, defaultContent: '' },
{ data: 'created', name: 'created_at' },
],
});
</script>
@endpush

View File

@@ -0,0 +1,14 @@
@push('shortcuts')
<dl class="dl-horizontal">
<dt><code>b</code></dt>
<dd>{{ trans('admin::admin.shortcuts.back_to_index', ['name' => trans('slider::sliders.slider')]) }}</dd>
</dl>
@endpush
@push('scripts')
<script>
keypressAction([
{ key: 'b', route: "{{ route('admin.sliders.index') }}" }
]);
</script>
@endpush

View File

@@ -0,0 +1,7 @@
<div class="form-group">
<div class="col-md-10">
<button type="submit" class="btn btn-primary" data-loading>
{{ trans('admin::admin.buttons.save') }}
</button>
</div>
</div>

View File

@@ -0,0 +1,15 @@
<div class="row">
<div class="col-md-8">
{{ Form::text('name', trans('slider::attributes.name'), $errors, $slider, ['required' => true]) }}
{{ Form::number('speed', trans('slider::attributes.speed'), $errors, $slider, ['placeholder' => trans('slider::sliders.form.300ms')]) }}
{{ Form::checkbox('fade', trans('slider::attributes.fade'), trans('slider::sliders.form.use_fade_instead_of_slide'), $errors, $slider) }}
{{ Form::checkbox('autoplay', trans('slider::attributes.autoplay'), trans('slider::sliders.form.enable_autoplay'), $errors, $slider, ['checked' => true]) }}
<div class="autoplay-speed-field {{ ($slider->autoplay ?? true) ? '' : 'hide' }}">
{{ Form::number('autoplay_speed', trans('slider::attributes.autoplay_speed'), $errors, $slider, ['placeholder' => trans('slider::sliders.form.3000ms'), 'checked' => true]) }}
</div>
{{ Form::checkbox('dots', trans('slider::attributes.dots'), trans('slider::sliders.form.show_dots'), $errors, $slider, ['checked' => true]) }}
{{ Form::checkbox('arrows', trans('slider::attributes.arrows'), trans('slider::sliders.form.show_arrows'), $errors, $slider, ['checked' => true]) }}
</div>
</div>

View File

@@ -0,0 +1,17 @@
<div id="slides-wrapper" class="clearfix">
{{-- Slides will be added here dynamically using JS --}}
</div>
<div class="form-group">
<button type="button" class="add-slide btn btn-default m-l-15">
{{ trans('slider::sliders.slide.add_slide') }}
</button>
</div>
@include('slider::admin.sliders.templates.slide')
@push('globals')
<script>
FleetCart.data['slider.slides'] = {!! old_json('slides', $slider->slides) !!};
</script>
@endpush

View File

@@ -0,0 +1,43 @@
<div class="slide-options call-to-action">
<h4>{{ trans("slider::sliders.slide.form.call_to_action") }}</h4>
<div class="form-group">
<div class="col-md-12 p-l-0">
<label class="control-label col-lg-2 col-md-3 col-sm-3 col-xs-12 text-left p-l-0" for="call-to-action-delay">
{{ trans("slider::attributes.call_to_action_delay") }}
</label>
<div class="col-lg-4 col-md-7 col-sm-6 col-xs-7 p-l-0">
<input type="number"
name="slides[<%- slideNumber %>][options][call_to_action][delay]"
class="form-control"
id="call-to-action-delay"
placeholder="{{ trans('slider::sliders.slide.form.0_7s') }}"
value="<%- slide.options.call_to_action.delay %>"
step="0.01"
>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-12 p-l-0">
<label class="control-label col-lg-2 col-md-3 col-sm-3 col-xs-12 text-left p-l-0" for="call-to-action-effect">
{{ trans("slider::attributes.call_to_action_effect") }}
</label>
<div class="col-lg-4 col-md-7 col-sm-6 col-xs-7 p-l-0">
<select name="slides[<%- slideNumber %>][options][call_to_action][effect]"
class="form-control custom-select-black"
id="call-to-action-effect"
>
@foreach (trans('slider::sliders.effects') as $effect => $name)
<option value="{{ $effect }}" <%= slide.options.call_to_action.effect === '{{ $effect }}' ? 'selected' : '' %>>
{{ $name }}
</option>
@endforeach
</select>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,43 @@
<div class="slide-options caption-{{ $captionNumber }}">
<h4>{{ trans("slider::sliders.slide.form.caption_{$captionNumber}") }}</h4>
<div class="form-group">
<div class="col-md-12 p-l-0">
<label class="control-label col-lg-2 col-md-3 col-sm-3 col-xs-12 text-left p-l-0" for="slides-<%- slideNumber %>-caption-{{ $captionNumber }}-delay">
{{ trans("slider::attributes.caption_{$captionNumber}_delay") }}
</label>
<div class="col-lg-4 col-md-7 col-sm-6 col-xs-7 p-l-0">
<input type="number"
name="slides[<%- slideNumber %>][options][caption_{{ $captionNumber }}][delay]"
class="form-control"
id="slides-<%- slideNumber %>-caption-{{ $captionNumber }}-delay"
placeholder="{{ trans('slider::sliders.slide.form.' . ($captionNumber === 1 ? '0s' : '0_3s')) }}"
value="<%- slide.options.caption_{{ $captionNumber }}.delay %>"
step="0.01"
>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-12 p-l-0">
<label class="control-label col-lg-2 col-md-3 col-sm-3 col-xs-12 text-left p-l-0" for="slides-<%- slideNumber %>-caption-{{ $captionNumber }}-effect">
{{ trans("slider::attributes.caption_{$captionNumber}_effect") }}
</label>
<div class="col-lg-4 col-md-7 col-sm-6 col-xs-7 p-l-0">
<select name="slides[<%- slideNumber %>][options][caption_{{ $captionNumber }}][effect]"
class="form-control custom-select-black"
id="slides-<%- slideNumber %>-caption-{{ $captionNumber }}-effect"
>
@foreach (trans('slider::sliders.effects') as $effect => $name)
<option value="{{ $effect }}" <%= slide.options.caption_{{ $captionNumber }}.effect === '{{ $effect }}' ? 'selected' : '' %>>
{{ $name }}
</option>
@endforeach
</select>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,166 @@
<script type="text/html" id="slide-template">
<div class="slide">
<div class="slide-header clearfix">
<span class="slide-drag pull-left">
<i class="fa">&#xf142;</i>
<i class="fa">&#xf142;</i>
</span>
<span class="pull-left">
{{ trans('slider::sliders.slide.image_slide') }}
</span>
<button type="button" class="delete-slide btn pull-right">
<i class="fa fa-times"></i>
</button>
</div>
<div class="slide-body">
<input type="hidden" name="slides[<%- slideNumber %>][id]" value="<%- slide.id %>">
<div class="slide-image" data-slide-number="<%- slideNumber %>">
<% if (slide.file && slide.file.path) { %>
<img src="<%- slide.file.path %>" alt="slide-image">
<input type="hidden" name="slides[<%- slideNumber %>][file_id]" value="<%- slide.file.id %>">
<% } else { %>
<i class="fa fa-picture-o"></i>
<% } %>
</div>
<div class="slide-tabs tab-wrapper">
<ul class="nav nav-tabs">
<li class="active">
<a href="#slides-<%- slideNumber %>-general" data-toggle="tab">
{{ trans('slider::sliders.slide.form.tabs.general') }}
</a>
</li>
<li>
<a href="#slider-<%- slideNumber %>-options" data-toggle="tab">
{{ trans('slider::sliders.slide.form.tabs.options') }}
</a>
</li>
</ul>
<div class="tab-content">
<div id="slides-<%- slideNumber %>-general" class="general tab-pane fade in active">
<div class="row">
<div class="col-lg-4 col-md-6">
<div class="form-group">
<label for="slides-<%- slideNumber %>-caption-1">
{{ trans('slider::attributes.caption_1') }}
</label>
<input type="text"
name="slides[<%- slideNumber %>][caption_1]"
class="form-control"
id="slides-<%- slideNumber %>-caption-1"
value="<%- slide.caption_1 %>"
>
</div>
</div>
<div class="col-lg-4 col-md-6">
<div class="form-group">
<label for="slides-<%- slideNumber %>-caption-2">
{{ trans('slider::attributes.caption_2') }}
</label>
<input type="text"
name="slides[<%- slideNumber %>][caption_2]"
class="form-control"
id="slides-<%- slideNumber %>-caption-2"
value="<%- slide.caption_2 %>"
>
</div>
</div>
<div class="col-lg-4 col-md-6">
<div class="form-group">
<label for="slides-<%- slideNumber %>-direction">
{{ trans('slider::attributes.direction') }}
</label>
<select
name="slides[<%- slideNumber %>][direction]"
class="form-control"
id="slides-<%- slideNumber %>-direction"
value="<%- slide.direction %>"
>
<option value="left" <%= slide.direction === 'left' ? 'selected' : '' %>>
{{ trans('slider::sliders.slide.form.directions.left') }}
</option>
<option value="right" <%= slide.direction === 'right' ? 'selected' : '' %>>
{{ trans('slider::sliders.slide.form.directions.right') }}
</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-4 col-md-6">
<div class="form-group">
<label for="slides[<%- slideNumber %>][call-to-action-text]">
{{ trans('slider::attributes.call_to_action_text') }}
</label>
<input type="text"
name="slides[<%- slideNumber %>][call_to_action_text]"
class="form-control"
id="slides[<%- slideNumber %>][call-to-action-text]"
value="<%- slide.call_to_action_text %>"
>
</div>
</div>
<div class="col-lg-4 col-md-6">
<div class="form-group">
<label for="slides-<%- slideNumber %>-call-to-action-url">
{{ trans('slider::attributes.call_to_action_url') }}
</label>
<input type="text"
name="slides[<%- slideNumber %>][call_to_action_url]"
class="form-control"
id="slides-<%- slideNumber %>-call-to-action-url"
value="<%- slide.call_to_action_url %>"
>
</div>
</div>
<div class="col-lg-4 col-md-12">
<div class="checkbox">
<input type="hidden" name="slides[<%- slideNumber %>][open_in_new_window]" value="0">
<input type="checkbox"
name="slides[<%- slideNumber %>][open_in_new_window]"
value="1"
id="slides-<%- slideNumber %>-open-in-new-window"
<%= slide.open_in_new_window ? 'checked' : '' %>
>
<label for="slides-<%- slideNumber %>-open-in-new-window">
{{ trans('slider::attributes.open_in_new_window') }}
</label>
</div>
</div>
</div>
</div>
<div id="slider-<%- slideNumber %>-options" class="tab-pane fade in clearfix">
<select class="change-option-block custom-select-black pull-right">
<option value="caption-1" selected>{{ trans('slider::sliders.slide.form.caption_1') }}</option>
<option value="caption-2">{{ trans('slider::sliders.slide.form.caption_2') }}</option>
<option value="call-to-action">{{ trans('slider::sliders.slide.form.call_to_action') }}</option>
</select>
@include('slider::admin.sliders.templates.partials.slide_caption', ['captionNumber' => 1])
@include('slider::admin.sliders.templates.partials.slide_caption', ['captionNumber' => 2])
@include('slider::admin.sliders.templates.partials.slide_call_to_action')
</div>
</div>
</div>
</div>
</div>
</script>

View File

@@ -0,0 +1,75 @@
<?php
use Illuminate\Support\Facades\Route;
Route::get('sliders', [
'as' => 'admin.sliders.index',
'uses' => 'SliderController@index',
'middleware' => 'can:admin.sliders.index',
]);
Route::get('sliders/create', [
'as' => 'admin.sliders.create',
'uses' => 'SliderController@create',
'middleware' => 'can:admin.sliders.create',
]);
Route::post('sliders', [
'as' => 'admin.sliders.store',
'uses' => 'SliderController@store',
'middleware' => 'can:admin.sliders.create',
]);
Route::get('sliders/{id}/edit', [
'as' => 'admin.sliders.edit',
'uses' => 'SliderController@edit',
'middleware' => 'can:admin.sliders.edit',
]);
Route::put('sliders/{id}', [
'as' => 'admin.sliders.update',
'uses' => 'SliderController@update',
'middleware' => 'can:admin.sliders.edit',
]);
Route::delete('sliders/{ids?}', [
'as' => 'admin.sliders.destroy',
'uses' => 'SliderController@destroy',
'middleware' => 'can:admin.sliders.destroy',
]);
Route::get('slider-options', [
'as' => 'admin.slider_options.index',
'uses' => 'SliderOptionController@index',
'middleware' => 'can:admin.slider_options.index',
]);
Route::get('slider-options/create', [
'as' => 'admin.slider_options.create',
'uses' => 'SliderOptionController@create',
'middleware' => 'can:admin.slider_options.create',
]);
Route::post('slider-options', [
'as' => 'admin.slider_options.store',
'uses' => 'SliderOptionController@store',
'middleware' => 'can:admin.slider_options.create',
]);
Route::get('slider-options/{id}/edit', [
'as' => 'admin.slider_options.edit',
'uses' => 'SliderOptionController@edit',
'middleware' => 'can:admin.slider_options.edit',
]);
Route::put('slider-options/{id}', [
'as' => 'admin.slider_options.update',
'uses' => 'SliderOptionController@update',
'middleware' => 'can:admin.slider_options.edit',
]);
Route::delete('slider-options/{ids?}', [
'as' => 'admin.slider_options.destroy',
'uses' => 'SliderOptionController@destroy',
'middleware' => 'can:admin.slider_options.destroy',
]);

View File

@@ -0,0 +1,26 @@
<?php
namespace Modules\Slider\Sidebar;
use Maatwebsite\Sidebar\Item;
use Maatwebsite\Sidebar\Menu;
use Maatwebsite\Sidebar\Group;
use Modules\Admin\Sidebar\BaseSidebarExtender;
class SidebarExtender extends BaseSidebarExtender
{
public function extend(Menu $menu)
{
$menu->group(trans('admin::sidebar.system'), function (Group $group) {
$group->item(trans('admin::sidebar.appearance'), function (Item $item) {
$item->item(trans('slider::sliders.sliders'), function (Item $item) {
$item->weight(5);
$item->route('admin.sliders.index');
$item->authorize(
$this->auth->hasAccess('admin.sliders.index')
);
});
});
});
}
}

View File

@@ -0,0 +1,27 @@
{
"name": "fleetcart/slider",
"description": "The FleetCart Slider Module.",
"authors": [
{
"name": "Envay Soft",
"email": "envaysoft@gmail.com"
}
],
"require": {
"php": "^8.0.2"
},
"autoload": {
"psr-4": {
"Modules\\Slider\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev"
}

View File

@@ -0,0 +1,9 @@
{
"name": "Slider",
"alias": "slider",
"description": "The FleetCart Slider Module.",
"priority": 100,
"providers": [
"Modules\\Slider\\Providers\\SliderServiceProvider"
]
}

View File

@@ -0,0 +1,8 @@
let mix = require('laravel-mix');
let execSync = require('child_process').execSync;
mix.js(`${__dirname}/Resources/assets/admin/js/main.js`, `${__dirname}/Assets/admin/js/slider.js`)
.sass(`${__dirname}/Resources/assets/admin/sass/main.scss`, `${__dirname}/Assets/admin/css/slider.css`)
.then(() => {
execSync(`npm run rtlcss ${__dirname}/Assets/admin/css/slider.css ${__dirname}/Assets/admin/css/slider.rtl.css`);
});