Page Plus
Changed the text editor
This commit is contained in:
parent
ce1fe12b94
commit
e003ffa38a
37 changed files with 1443 additions and 0 deletions
24
Config/config.php
Normal file
24
Config/config.php
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
'name' => 'PagePlus',
|
||||||
|
'icon' => 'https://imgur.png',
|
||||||
|
'author' => 'GIGABAIT',
|
||||||
|
'version' => '1.0.0',
|
||||||
|
'wemx_version' => '>=2.0.0',
|
||||||
|
|
||||||
|
'elements' => [
|
||||||
|
'admin_menu' =>
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'name' => 'PagePlus',
|
||||||
|
'icon' => '<i class="fas fa-list"></i>',
|
||||||
|
'href' => '/admin/pageplus',
|
||||||
|
'style' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('page_pluses', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedBigInteger('parent_id')->nullable();
|
||||||
|
$table->string('slug')->unique();
|
||||||
|
$table->integer('order')->default(0);
|
||||||
|
$table->timestamps();
|
||||||
|
$table->foreign('parent_id')->references('id')->on('page_pluses')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('page_pluses');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('page_plus_translations', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('page_id')->constrained('page_pluses')->onDelete('cascade');
|
||||||
|
$table->string('locale', 10)->default('en');
|
||||||
|
$table->string('title');
|
||||||
|
$table->longText('content');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('page_plus_translations');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('page_plus_metas', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('page_id')->constrained('page_pluses')->onDelete('cascade');
|
||||||
|
$table->string('key');
|
||||||
|
$table->text('value');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('page_plus_metas');
|
||||||
|
}
|
||||||
|
};
|
54
Entities/PageHelper.php
Normal file
54
Entities/PageHelper.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Entities;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Modules\PagePlus\Http\Controllers\PagePlusController;
|
||||||
|
|
||||||
|
class PageHelper
|
||||||
|
{
|
||||||
|
public static function registerRoutes($page = null, $pathPrefix = ''): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$pages = is_null($page) ? PagePlus::whereNull('parent_id')->get() : $page->children;
|
||||||
|
foreach ($pages as $page) {
|
||||||
|
$path = $pathPrefix . '/' . $page->slug;
|
||||||
|
Route::get($path, [PagePlusController::class, 'show'])->name(str_replace('/', '.', $page->slug))->defaults('slug', $page->slug);
|
||||||
|
if ($page->children()->count() > 0) {
|
||||||
|
self::registerRoutes($page, $path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
ErrorLog('pageplus', $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cacheKey($key, $id): string
|
||||||
|
{
|
||||||
|
return sprintf('pagePlus_%s_%s', $key, $id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function clearAllCache(): void
|
||||||
|
{
|
||||||
|
// Clear cache for PagePlus
|
||||||
|
$pagePlusIds = PagePlus::pluck('id');
|
||||||
|
foreach ($pagePlusIds as $id) {
|
||||||
|
Cache::forget(self::cacheKey('fullSlug', $id));
|
||||||
|
Cache::forget(self::cacheKey('childrenIds', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear cache for PagePlusMeta
|
||||||
|
$pagePlusMeta = PagePlusMeta::all();
|
||||||
|
foreach ($pagePlusMeta as $meta) {
|
||||||
|
Cache::forget(self::cacheKey('meta', $meta->page_id) . '_' . $meta->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear cache for PagePlusTranslation
|
||||||
|
$pagePlusTranslations = PagePlusTranslation::all();
|
||||||
|
foreach ($pagePlusTranslations as $translation) {
|
||||||
|
Cache::forget(self::cacheKey('translation', $translation->page_id) . '_' . $translation->locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
146
Entities/PagePlus.php
Normal file
146
Entities/PagePlus.php
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Entities;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class PagePlus extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['parent_id', 'slug', 'icon', 'created_by', 'updated_by', 'order'];
|
||||||
|
|
||||||
|
protected static function booted(): void
|
||||||
|
{
|
||||||
|
static::addGlobalScope('order', function (Builder $builder) {
|
||||||
|
$builder->orderBy('order');
|
||||||
|
});
|
||||||
|
|
||||||
|
$clearCache = function ($model) {
|
||||||
|
Cache::forget(PageHelper::cacheKey('fullSlug', $model->id));
|
||||||
|
Cache::forget(PageHelper::cacheKey('childrenIds', $model->id));
|
||||||
|
Cache::forget(PageHelper::cacheKey('bySlug', $model->slug));
|
||||||
|
Cache::forget(PageHelper::cacheKey('children', $model->parent_id));
|
||||||
|
Cache::forget(PageHelper::cacheKey('topmostAncestor', $model->id));
|
||||||
|
if ($parent = $model->parent()->first()) {
|
||||||
|
Cache::forget(PageHelper::cacheKey('fullSlug', $parent->id));
|
||||||
|
Cache::forget(PageHelper::cacheKey('childrenIds', $parent->id));
|
||||||
|
Cache::forget(PageHelper::cacheKey('children', $parent->id));
|
||||||
|
Cache::forget(PageHelper::cacheKey('topmostAncestor', $parent->id));
|
||||||
|
}
|
||||||
|
$allLocations = PagePlusMeta::where('key', 'location')->pluck('value')->unique();
|
||||||
|
foreach ($allLocations as $location) {
|
||||||
|
Cache::forget(PageHelper::cacheKey('byLocation', $location));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static::saved($clearCache);
|
||||||
|
static::deleted($clearCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function metas(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(PagePlusMeta::class, 'page_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function translations(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(PagePlusTranslation::class, 'page_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parent(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PagePlus::class, 'parent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function children(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(PagePlus::class, 'parent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function childrenCached()
|
||||||
|
{
|
||||||
|
return Cache::rememberForever(PageHelper::cacheKey('children', $this->id), function () {
|
||||||
|
return $this->children()->orderBy('order')->get();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFullSlug(): string
|
||||||
|
{
|
||||||
|
return Cache::rememberForever(PageHelper::cacheKey('fullSlug', $this->id), function () {
|
||||||
|
$slugs = [];
|
||||||
|
$page = $this;
|
||||||
|
while ($page) {
|
||||||
|
array_unshift($slugs, $page->slug);
|
||||||
|
$page = $page->parent;
|
||||||
|
}
|
||||||
|
return implode('/', $slugs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMeta($key, $default = null): ?string
|
||||||
|
{
|
||||||
|
$cacheKey = PageHelper::cacheKey('meta', $this->id) . '_' . $key;
|
||||||
|
return Cache::rememberForever($cacheKey, function () use ($key, $default) {
|
||||||
|
$meta = $this->metas()->where('key', $key)->first();
|
||||||
|
return $meta ? $meta->value : $default;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTranslation($locale = null)
|
||||||
|
{
|
||||||
|
$locale = $locale ?? (auth()->check() ? auth()->user()->language : app()->getLocale());
|
||||||
|
$cacheKey = PageHelper::cacheKey('translation', $this->id) . '_' . $locale;
|
||||||
|
return Cache::rememberForever($cacheKey, function () use ($locale) {
|
||||||
|
$translation = $this->translations()->where('locale', $locale)->first();
|
||||||
|
return $translation ?: $this->translations()->orderBy('created_at', 'asc')->first();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllChildrenIds(): array
|
||||||
|
{
|
||||||
|
return Cache::rememberForever(PageHelper::cacheKey('childrenIds', $this->id), function () {
|
||||||
|
$ids = [];
|
||||||
|
foreach ($this->children as $child) {
|
||||||
|
$ids[] = $child->id;
|
||||||
|
$ids = array_merge($ids, $child->getAllChildrenIds());
|
||||||
|
}
|
||||||
|
return $ids;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function availableParents()
|
||||||
|
{
|
||||||
|
$excludedIds = $this->getAllChildrenIds();
|
||||||
|
$excludedIds[] = $this->id;
|
||||||
|
return PagePlus::whereNotIn('id', $excludedIds)->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTopmostAncestor()
|
||||||
|
{
|
||||||
|
return Cache::rememberForever(PageHelper::cacheKey('topmostAncestor', $this->id), function () {
|
||||||
|
$ancestor = $this;
|
||||||
|
while ($ancestor->parent()->exists()) {
|
||||||
|
$ancestor = $ancestor->parent()->first();
|
||||||
|
}
|
||||||
|
return $ancestor;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function getBySlug($slug)
|
||||||
|
{
|
||||||
|
return Cache::rememberForever(PageHelper::cacheKey('bySlug', $slug), function () use ($slug) {
|
||||||
|
$slugs = explode('/', trim($slug, '/'));
|
||||||
|
$page = self::where('slug', array_shift($slugs))->firstOrFail();
|
||||||
|
foreach ($slugs as $slug) {
|
||||||
|
$page = $page->children()->where('slug', $slug)->firstOrFail();
|
||||||
|
}
|
||||||
|
return $page;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
29
Entities/PagePlusMeta.php
Normal file
29
Entities/PagePlusMeta.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Entities;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class PagePlusMeta extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['page_id', 'key', 'value'];
|
||||||
|
|
||||||
|
public function page(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PagePlus::class, 'page_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function booted(): void
|
||||||
|
{
|
||||||
|
static::saved(function ($meta) {
|
||||||
|
Cache::forget(PageHelper::cacheKey('meta', $meta->page_id) . '_' . $meta->key);
|
||||||
|
});
|
||||||
|
|
||||||
|
static::deleted(function ($meta) {
|
||||||
|
Cache::forget(PageHelper::cacheKey('meta', $meta->page_id) . '_' . $meta->key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
29
Entities/PagePlusTranslation.php
Normal file
29
Entities/PagePlusTranslation.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Entities;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
class PagePlusTranslation extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = ['page_id', 'locale', 'title', 'content'];
|
||||||
|
|
||||||
|
public function page(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(PagePlus::class, 'page_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function booted(): void
|
||||||
|
{
|
||||||
|
static::saved(function ($translation) {
|
||||||
|
Cache::forget(PageHelper::cacheKey('translation', $translation->page_id) . '_' . $translation->locale);
|
||||||
|
});
|
||||||
|
|
||||||
|
static::deleted(function ($translation) {
|
||||||
|
Cache::forget(PageHelper::cacheKey('translation', $translation->page_id) . '_' . $translation->locale);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
98
Http/Controllers/AdminPagePlusController.php
Normal file
98
Http/Controllers/AdminPagePlusController.php
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Facades\AdminTheme;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
|
use Modules\PagePlus\Entities\PageHelper;
|
||||||
|
use Modules\PagePlus\Entities\PagePlus;
|
||||||
|
use Modules\PagePlus\Rules\UniqueSlug;
|
||||||
|
|
||||||
|
class AdminPagePlusController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
PageHelper::clearAllCache();
|
||||||
|
$pages = PagePlus::whereNull('parent_id')->paginate(20);
|
||||||
|
return view(AdminTheme::moduleView('pageplus', 'index'), compact('pages'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(PagePlus $page = null)
|
||||||
|
{
|
||||||
|
$pages = PagePlus::get();
|
||||||
|
return view(AdminTheme::moduleView('pageplus', 'create'), compact('pages', 'page'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'id' => 'nullable|exists:page_pluses,id',
|
||||||
|
'parent_id' => 'nullable|exists:page_pluses,id',
|
||||||
|
'slug' => ['required', 'string', 'regex:/^[A-Za-z0-9\-_]+$/', new UniqueSlug($request->input('id'))],
|
||||||
|
'order' => 'required|integer',
|
||||||
|
'locale' => 'nullable|string',
|
||||||
|
'title' => 'nullable|string',
|
||||||
|
'content' => 'nullable|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$page = PagePlus::updateOrCreate(
|
||||||
|
['id' => $data['id'] ?? null],
|
||||||
|
['parent_id' => $data['parent_id'], 'slug' => $data['slug'], 'order' => $data['order']]
|
||||||
|
);
|
||||||
|
|
||||||
|
$page->translations()->updateOrCreate(
|
||||||
|
['locale' => $data['locale'] ?? app()->getLocale()],
|
||||||
|
['title' => $data['title'] ?? '', 'content' => $data['content'] ?? '']
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($request->has('meta')) {
|
||||||
|
foreach ($request->input('meta') as $key => $value) {
|
||||||
|
$page->metas()->updateOrCreate(
|
||||||
|
['key' => $key],
|
||||||
|
['value' => $value ?? '']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('admin.pageplus.index')->with('success', __('pageplus::messages.page_saved_success'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(PagePlus $page)
|
||||||
|
{
|
||||||
|
$page->delete();
|
||||||
|
return redirect()->route('admin.pageplus.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function translate(PagePlus $page, $locale = null)
|
||||||
|
{
|
||||||
|
$locale = $locale ?: app()->getLocale();
|
||||||
|
return view(AdminTheme::moduleView('pageplus', 'translate'), compact('page', 'locale'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function translateStore(Request $request, PagePlus $page)
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'locale' => 'required|string',
|
||||||
|
'title' => 'required|string',
|
||||||
|
'content' => 'required|string',
|
||||||
|
]);
|
||||||
|
$page->translations()->updateOrCreate(
|
||||||
|
['locale' => $data['locale']],
|
||||||
|
['title' => $data['title'], 'content' => $data['content']]
|
||||||
|
);
|
||||||
|
|
||||||
|
return redirect()->route('admin.pageplus.index')->with('success', __('pageplus::messages.translate_saved_success'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function changeOrder(PagePlus $page, $action = 'down')
|
||||||
|
{
|
||||||
|
if ($action == 'up') {
|
||||||
|
$page->increment('order');
|
||||||
|
} else {
|
||||||
|
$page->decrement('order');
|
||||||
|
}
|
||||||
|
return redirect()->back()->with('success', __('pageplus::messages.order_change_success'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
Http/Controllers/PagePlusController.php
Normal file
16
Http/Controllers/PagePlusController.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Facades\Theme;
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
|
use Modules\PagePlus\Entities\PagePlus;
|
||||||
|
|
||||||
|
class PagePlusController extends Controller
|
||||||
|
{
|
||||||
|
public function show($slug)
|
||||||
|
{
|
||||||
|
$page = PagePlus::getBySlug($slug);
|
||||||
|
return view(Theme::moduleView('pageplus', 'index'), compact('page'));
|
||||||
|
}
|
||||||
|
}
|
77
Providers/PagePlusServiceProvider.php
Normal file
77
Providers/PagePlusServiceProvider.php
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class PagePlusServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
protected string $moduleName = 'PagePlus';
|
||||||
|
|
||||||
|
protected string $moduleNameLower = 'pageplus';
|
||||||
|
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
$this->registerTranslations();
|
||||||
|
$this->registerViews();
|
||||||
|
$this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
|
||||||
|
$this->registerConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->app->register(RouteServiceProvider::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function registerConfig(): void
|
||||||
|
{
|
||||||
|
$this->publishes([
|
||||||
|
module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'),
|
||||||
|
], 'config');
|
||||||
|
$this->mergeConfigFrom(
|
||||||
|
module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerViews(): void
|
||||||
|
{
|
||||||
|
$viewPath = resource_path('views/modules/' . $this->moduleNameLower);
|
||||||
|
|
||||||
|
$sourcePath = module_path($this->moduleName, 'Resources/views');
|
||||||
|
|
||||||
|
$this->publishes([
|
||||||
|
$sourcePath => $viewPath
|
||||||
|
], ['views', $this->moduleNameLower . '-module-views']);
|
||||||
|
|
||||||
|
$this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerTranslations(): void
|
||||||
|
{
|
||||||
|
$langPath = resource_path('lang/modules/' . $this->moduleNameLower);
|
||||||
|
|
||||||
|
if (is_dir($langPath)) {
|
||||||
|
$this->loadTranslationsFrom($langPath, $this->moduleNameLower);
|
||||||
|
$this->loadJsonTranslationsFrom($langPath, $this->moduleNameLower);
|
||||||
|
} else {
|
||||||
|
$this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
|
||||||
|
$this->loadJsonTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provides(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPublishableViewPaths(): array
|
||||||
|
{
|
||||||
|
$paths = [];
|
||||||
|
foreach (\Config::get('view.paths') as $path) {
|
||||||
|
if (is_dir($path . '/modules/' . $this->moduleNameLower)) {
|
||||||
|
$paths[] = $path . '/modules/' . $this->moduleNameLower;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $paths;
|
||||||
|
}
|
||||||
|
}
|
32
Providers/RouteServiceProvider.php
Normal file
32
Providers/RouteServiceProvider.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
|
class RouteServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
protected string $moduleNamespace = 'Modules\PagePlus\Http\Controllers';
|
||||||
|
|
||||||
|
public function map(): void
|
||||||
|
{
|
||||||
|
$this->mapAdminRoutes();
|
||||||
|
$this->mapWebRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function mapWebRoutes(): void
|
||||||
|
{
|
||||||
|
Route::middleware('web')
|
||||||
|
->namespace($this->moduleNamespace)
|
||||||
|
->group(module_path('PagePlus', '/Routes/web.php'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function mapAdminRoutes(): void
|
||||||
|
{
|
||||||
|
Route::prefix('admin')
|
||||||
|
->middleware(['web'])
|
||||||
|
->namespace($this->moduleNamespace)
|
||||||
|
->group(module_path('PagePlus', '/Routes/admin.php'));
|
||||||
|
}
|
||||||
|
}
|
39
Resources/lang/en/messages.php
Normal file
39
Resources/lang/en/messages.php
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'title' => 'Title',
|
||||||
|
'edit_page' => 'Edit Page',
|
||||||
|
'create_page' => 'Create Page',
|
||||||
|
'back' => 'Back',
|
||||||
|
'slug' => 'Slug',
|
||||||
|
'icon' => 'Icon',
|
||||||
|
'order' => 'Order',
|
||||||
|
'parent_page' => 'Parent Page',
|
||||||
|
'redirect_url' => 'Redirect URL',
|
||||||
|
'page_location' => 'Page Location',
|
||||||
|
'update_page' => 'Update Page',
|
||||||
|
'no_location' => 'No Location',
|
||||||
|
'navbar' => 'Navbar',
|
||||||
|
'header_right' => 'Header Right',
|
||||||
|
'header_left' => 'Header Left',
|
||||||
|
'user_dropdown' => 'User Dropdown',
|
||||||
|
'app_dropdown' => 'App Dropdown',
|
||||||
|
'help_footer' => 'Help Center (footer)',
|
||||||
|
'legal_footer' => 'Legal (footer)',
|
||||||
|
'resources_footer' => 'Resources (footer)',
|
||||||
|
'pages' => 'Pages',
|
||||||
|
'actions' => 'Actions',
|
||||||
|
'translation_page' => 'Translation Page',
|
||||||
|
'language' => 'Language',
|
||||||
|
'save_translation' => 'Save Translation',
|
||||||
|
'content' => 'Content',
|
||||||
|
'move_up' => 'Move Up',
|
||||||
|
'move_down' => 'Move Down',
|
||||||
|
'go_to_page' => 'Go to page',
|
||||||
|
'translate' => 'Translate',
|
||||||
|
'edit' => 'Edit',
|
||||||
|
'delete' => 'Delete',
|
||||||
|
'page_saved_success' => 'Page saved successfully.',
|
||||||
|
'translate_saved_success' => 'Page translated successfully.',
|
||||||
|
'order_change_success' => 'Order changed successfully.',
|
||||||
|
];
|
39
Resources/lang/uk/messages.php
Normal file
39
Resources/lang/uk/messages.php
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'title' => 'Назва',
|
||||||
|
'edit_page' => 'Редагувати сторінку',
|
||||||
|
'create_page' => 'Створити сторінку',
|
||||||
|
'back' => 'Назад',
|
||||||
|
'slug' => 'Урл (slug)',
|
||||||
|
'icon' => 'Значок',
|
||||||
|
'order' => 'Порядок',
|
||||||
|
'parent_page' => 'Батьківська сторінка',
|
||||||
|
'redirect_url' => 'URL-адреса перенаправлення',
|
||||||
|
'page_location' => 'Розташування сторінки',
|
||||||
|
'update_page' => 'Сторінка оновлення',
|
||||||
|
'no_location' => 'Без розташування',
|
||||||
|
'navbar' => 'Навігаційна панель',
|
||||||
|
'header_right' => 'Заголовок справа',
|
||||||
|
'header_left' => 'Заголовок ліворуч',
|
||||||
|
'user_dropdown' => 'Випадаюче меню користувача',
|
||||||
|
'app_dropdown' => 'Випадаюче меню програми',
|
||||||
|
'help_footer' => 'Довідковий центр (footer)',
|
||||||
|
'legal_footer' => 'Юридична інформація (footer)',
|
||||||
|
'resources_footer' => 'Ресурси (footer)',
|
||||||
|
'pages' => 'Сторінки',
|
||||||
|
'actions' => 'Дії',
|
||||||
|
'translation_page' => 'Сторінка перекладу',
|
||||||
|
'language' => 'Мова',
|
||||||
|
'save_translation' => 'Зберегти переклад',
|
||||||
|
'content' => 'Зміст',
|
||||||
|
'move_up' => 'Перемістити вгору',
|
||||||
|
'move_down' => 'Перемістити вниз',
|
||||||
|
'go_to_page' => 'Перейти на сторінку',
|
||||||
|
'translate' => 'Переклад',
|
||||||
|
'edit' => 'Редагувати',
|
||||||
|
'delete' => 'Видалити',
|
||||||
|
'page_saved_success' => 'Сторінку успішно збережено.',
|
||||||
|
'translate_saved_success' => 'Сторінку успішно перекладено.',
|
||||||
|
'order_change_success' => 'Порядок успішно змінено.',
|
||||||
|
];
|
123
Resources/views/admin/default/create.blade.php
Normal file
123
Resources/views/admin/default/create.blade.php
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
@extends(AdminTheme::wrapper(), ['title' => $page ? __('pageplus::messages.edit_page') : __('pageplus::messages.create_page'), 'keywords' => 'WemX Dashboard, WemX Panel'])
|
||||||
|
|
||||||
|
@section('container')
|
||||||
|
<link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="card card-primary card-outline">
|
||||||
|
<div class="card-header d-flex justify-content-between">
|
||||||
|
<h4 class="card-title text-center">{{ $page ? __('pageplus::messages.edit_page') : __('pageplus::messages.create_page') }}</h4>
|
||||||
|
<div class="card-tools text-center">
|
||||||
|
<a href="{{ route('admin.pageplus.index') }}" class="btn btn-primary btn-sm">{!! __('pageplus::messages.back') !!}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="{{ route('admin.pageplus.store') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
@if($page)
|
||||||
|
<input type="hidden" name="id" value="{{ $page->id }}">
|
||||||
|
@endif
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title">{!! __('pageplus::messages.title') !!}</label>
|
||||||
|
<input type="text" class="form-control" id="title" name="title" placeholder="Title" value="{{ old('title', optional($page)->getTranslation(app()->getLocale())->title ?? '') }}">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="slug">{!! __('pageplus::messages.slug') !!}</label>
|
||||||
|
<input type="text" class="form-control" id="slug" name="slug" placeholder="Slug" value="{{ old('slug', $page->slug ?? '') }}">
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-toggle="modal" data-target="#IconModal">
|
||||||
|
<label for="icon">{!! __('pageplus::messages.icon') !!}</label>
|
||||||
|
<input class="form-control" id="icon" name="meta[icon]" value="{{ old('meta.icon', optional($page)->getMeta('icon') ?? '') }}" placeholder="<i class='bx bx-info-circle'></i>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="order">{!! __('pageplus::messages.order') !!}</label>
|
||||||
|
<input type="number" class="form-control" id="order" name="order" placeholder="Order" value="{{ old('order', $page->order ?? '') }}">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="parent_id">{!! __('pageplus::messages.parent_page') !!}</label>
|
||||||
|
<select class="form-control" id="parent_id" name="parent_id">
|
||||||
|
<option value="">No Parent</option>
|
||||||
|
@foreach(optional($page)->availableParents() ?? $pages as $parentPage)
|
||||||
|
@if(!isset($page) || (isset($page) && $page->id !== $parentPage->id))
|
||||||
|
<option value="{{ $parentPage->id }}" @if(isset($page) && $page->parent_id == $parentPage->id) selected @endif>{{ $parentPage->slug }}</option>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="redirect">{!! __('pageplus::messages.redirect_url') !!}</label>
|
||||||
|
<input class="form-control" id="redirect" name="meta[redirect]" value="{{ old('meta.redirect', optional($page)->getMeta('redirect') ?? '') }}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@include(AdminTheme::moduleView('pageplus', 'editor'), ['content' => old('content', optional($page)->getTranslation(app()->getLocale())->content ?? ''), 'name' => 'content', 'label' => 'Content'])
|
||||||
|
@if(!$page or !$page->parent_id)
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="location">{!! __('pageplus::messages.page_location') !!}</label>
|
||||||
|
<select class="form-control" id="location" name="meta[location]">
|
||||||
|
<option value="none" {{ (old('meta.location', optional($page)->getMeta('location')) == 'none') ? 'selected' : '' }}>{!! __('pageplus::messages.no_location') !!}</option>
|
||||||
|
<option value="main-menu" {{ (old('meta.location', optional($page)->getMeta('location')) == 'main-menu') ? 'selected' : '' }}>{!! __('pageplus::messages.navbar') !!}</option>
|
||||||
|
<option value="navbar-dropdown-right" {{ (old('meta.location', optional($page)->getMeta('location')) == 'navbar-dropdown-right') ? 'selected' : '' }}>{!! __('pageplus::messages.header_right') !!}</option>
|
||||||
|
<option value="navbar-dropdown-left" {{ (old('meta.location', optional($page)->getMeta('location')) == 'navbar-dropdown-left') ? 'selected' : '' }}>{!! __('pageplus::messages.header_left') !!}</option>
|
||||||
|
<option value="user-dropdown" {{ (old('meta.location', optional($page)->getMeta('location')) == 'user-dropdown') ? 'selected' : '' }}>{!! __('pageplus::messages.user_dropdown') !!}</option>
|
||||||
|
<option value="app-dropdown" {{ (old('meta.location', optional($page)->getMeta('location')) == 'app-dropdown') ? 'selected' : '' }}>{!! __('pageplus::messages.app_dropdown') !!}</option>
|
||||||
|
<option value="footer-help" {{ (old('meta.location', optional($page)->getMeta('location')) == 'footer-help') ? 'selected' : '' }}>{!! __('pageplus::messages.help_footer') !!}</option>
|
||||||
|
<option value="footer-legal" {{ (old('meta.location', optional($page)->getMeta('location')) == 'footer-legal') ? 'selected' : '' }}>{!! __('pageplus::messages.legal_footer') !!}</option>
|
||||||
|
<option value="footer-resources" {{ (old('meta.location', optional($page)->getMeta('location')) == 'footer-resources') ? 'selected' : '' }}>{!! __('pageplus::messages.resources_footer') !!}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">{{ $page ? __('pageplus::messages.update_page') : __('pageplus::messages.create_page') }}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="IconModal" tabindex="-1" role="dialog"
|
||||||
|
aria-labelledby="IconModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title"
|
||||||
|
id="IconModalLabel">{{ __('admin.select_icon') }}</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="{{ __('admin.close') }}">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
@foreach(config('utils.icons') as $icon)
|
||||||
|
<div class="col-1 mb-4">
|
||||||
|
<div class="bx-md d-flex justify-content-center"
|
||||||
|
style="cursor: pointer;" onclick='setIcon("{{ $icon }}")'>
|
||||||
|
{!! $icon !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
<div class="form-group col-md-12 col-12">
|
||||||
|
<label for="custom-icon">{{ __('admin.icon_font') }}</label>
|
||||||
|
<input type="text" name="description" id="custom-icon" value="" class="form-control" required=""/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary"
|
||||||
|
data-dismiss="modal">{{ __('admin.close') }}</button>
|
||||||
|
<button type="button" onclick="setPageIcon()" class="btn btn-primary"
|
||||||
|
data-dismiss="modal">{{ __('admin.use_icon') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function setIcon(icon) {
|
||||||
|
document.getElementById("custom-icon").value = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPageIcon() {
|
||||||
|
document.getElementById("icon").value = document.getElementById("custom-icon").value;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@endsection
|
17
Resources/views/admin/default/editor.blade.php
Normal file
17
Resources/views/admin/default/editor.blade.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
@section('css_libraries')
|
||||||
|
<link rel="stylesheet" href="{{ asset(AdminTheme::assets('modules/summernote/summernote-bs4.css')) }}"/>
|
||||||
|
<link rel="stylesheet" href="{{ asset(AdminTheme::assets('modules/select2/dist/css/select2.min.css')) }}">
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('js_libraries')
|
||||||
|
<script src="{{ asset(AdminTheme::assets('modules/summernote/summernote-bs4.js')) }}"></script>
|
||||||
|
<script src="{{ asset(AdminTheme::assets('modules/select2/dist/js/select2.full.min.js')) }}"></script>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
<textarea class="summernote form-control @error('description') is-invalid @enderror" name="content" id="content" style="height: 200px !important"></textarea>
|
||||||
|
|
||||||
|
@php($plugins = 'preview importcss searchreplace autolink autosave save directionality code visualblocks visualchars fullscreen image link media template codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help charmap quickbars emoticons accordion')
|
||||||
|
@php($toolbar = 'undo redo | accordion accordionremove | blocks fontfamily fontsize | bold italic underline strikethrough | align numlist bullist | link image | table media | lineheight outdent indent| forecolor backcolor removeformat | charmap emoticons | code fullscreen preview | save print | pagebreak anchor codesample | ltr rtl')
|
||||||
|
@php($menubar = 'file edit view insert format tools table help')
|
||||||
|
|
43
Resources/views/admin/default/index.blade.php
Normal file
43
Resources/views/admin/default/index.blade.php
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
@extends(AdminTheme::wrapper(), ['title' => __('pageplus::messages.pages'), 'keywords' => 'WemX Dashboard, WemX Panel'])
|
||||||
|
|
||||||
|
@section('container')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between">
|
||||||
|
<h3 class="card-title">{!! __('pageplus::messages.pages') !!}</h3>
|
||||||
|
<div class="card-tools">
|
||||||
|
<a href="{{ route('admin.pageplus.create') }}" class="btn btn-primary btn-sm">
|
||||||
|
{!! __('pageplus::messages.create_page') !!}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">{!! __('pageplus::messages.title') !!}</th>
|
||||||
|
<th scope="col">{!! __('pageplus::messages.slug') !!}</th>
|
||||||
|
<th scope="col">{!! __('pageplus::messages.order') !!}</th>
|
||||||
|
<th scope="col" class="text-right">{!! __('pageplus::messages.actions') !!}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<style>
|
||||||
|
tr {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.parent-page {
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@include(AdminTheme::moduleView('pageplus', 'page_children'), ['pages' => $pages, 'depth' => 0, 'prefix' => '', 'collapse' => false])
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{{ $pages->links() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
48
Resources/views/admin/default/page_children.blade.php
Normal file
48
Resources/views/admin/default/page_children.blade.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
@foreach($pages as $page)
|
||||||
|
<tr @if($depth > 0) id="children-{{ $prefix }}" class="collapse child-page" @else class="parent-page"
|
||||||
|
data-toggle="collapse" data-target="#children-{{ $page->id }}" @endif
|
||||||
|
@if($collapse) data-toggle="collapse" data-target="#children-{{ $page->id }}" @endif>
|
||||||
|
|
||||||
|
<td @if($depth > 0) style="padding-left: {{ $depth * 40 }}px" @endif >
|
||||||
|
<i class="fas {{ $page->children->isNotEmpty() ? 'fa-chevron-down' : 'fa-list' }} mr-1"></i>
|
||||||
|
{{ $page->getTranslation(app()->getLocale())->title }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>{{ $page->slug }}</td>
|
||||||
|
<td>{{ $page->order }}</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="{{ route('admin.pageplus.change_order', ['page' => $page->id, 'action' => 'down']) }}"
|
||||||
|
class="btn btn-info btn-sm" data-toggle="tooltip" title="{!! __('pageplus::messages.move_up') !!}">
|
||||||
|
<i class="fas fa-arrow-up"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.pageplus.change_order', ['page' => $page->id, 'action' => 'up']) }}"
|
||||||
|
class="btn btn-info btn-sm" data-toggle="tooltip" title="{!! __('pageplus::messages.move_down') !!}">
|
||||||
|
<i class="fas fa-arrow-down"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route($page->slug) }}" class="btn btn-warning btn-sm" target="_blank"
|
||||||
|
data-toggle="tooltip" title="{!! __('pageplus::messages.go_to_page') !!}">
|
||||||
|
<i class="fas fa-link"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.pageplus.translate', $page->id) }}" class="btn btn-primary btn-sm"
|
||||||
|
data-toggle="tooltip" title="{!! __('pageplus::messages.translate') !!}">
|
||||||
|
<i class="fas fa-language"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.pageplus.edit', $page->id) }}" class="btn btn-primary btn-sm" data-toggle="tooltip"
|
||||||
|
title="{!! __('pageplus::messages.edit') !!}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.pageplus.delete', $page->id) }}"
|
||||||
|
onclick="return confirm('{{ __('client.sure_you_want_delete') }}')" class="btn btn-danger btn-sm"
|
||||||
|
data-toggle="tooltip" title="{!! __('pageplus::messages.delete') !!}">
|
||||||
|
<i class="fas fa-trash-alt"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@if($page->children->isNotEmpty())
|
||||||
|
@include(AdminTheme::moduleView('pageplus', 'page_children'), ['pages' => $page->children, 'depth' => $depth + 1, 'prefix' => $page->id, 'collapse' => true])
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
|
||||||
|
|
45
Resources/views/admin/default/translate.blade.php
Normal file
45
Resources/views/admin/default/translate.blade.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
@extends(AdminTheme::wrapper(), ['title' => __('pageplus::messages.translation_page'), 'keywords' => 'WemX Dashboard, WemX Panel'])
|
||||||
|
|
||||||
|
@section('container')
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between">
|
||||||
|
<h4 class="card-title text-center">{!! __('pageplus::messages.translation_page') !!}</h4>
|
||||||
|
<div class="card-tools text-center">
|
||||||
|
<a href="{{ route('admin.pageplus.index') }}" class="btn btn-primary btn-sm">{!! __('pageplus::messages.back') !!}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="{{ route('admin.pageplus.translate.store', $page->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="locale">{!! __('pageplus::messages.language') !!}</label>
|
||||||
|
<select class="form-control" id="locale" name="locale"
|
||||||
|
onchange="window.location.href = '{{ route('admin.pageplus.translate', ['page' => $page->id]) }}'+'/'+this.value">
|
||||||
|
@if(Module::isEnabled('locales'))
|
||||||
|
@foreach(lang_module()->getInstalled() as $key => $lang)
|
||||||
|
<option @if($locale == $key) selected
|
||||||
|
@endif value="{{$key}}">{{$lang}}</option>
|
||||||
|
@endforeach
|
||||||
|
@else
|
||||||
|
<option value="en">English</option>
|
||||||
|
@endif
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title">{!! __('pageplus::messages.title') !!}</label>
|
||||||
|
<input type="text" class="form-control" id="title" name="title"
|
||||||
|
value="{{ optional($page)->getTranslation($locale)->title }}" required>
|
||||||
|
</div>
|
||||||
|
@include(AdminTheme::moduleView('pageplus', 'editor'), ['content' => optional($page)->getTranslation($locale)->content, 'name' => 'content', 'label' => __('pageplus::messages.content')])
|
||||||
|
<button type="submit" class="btn btn-primary">{!! __('pageplus::messages.save_translation') !!}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
13
Resources/views/client/tailwind/elements/apps.blade.php
Normal file
13
Resources/views/client/tailwind/elements/apps.blade.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
@php($pages = pages_by_location('app-dropdown'))
|
||||||
|
@if(count($pages))
|
||||||
|
@foreach($pages as $page)
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="group block rounded-lg p-4 text-center hover:bg-gray-100 dark:hover:bg-gray-600">
|
||||||
|
<div class="mx-auto mb-1 text-3xl text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400">
|
||||||
|
{!! $page->getMeta('icon') !!}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-900 dark:text-white"> {{ $page->getTranslation()->title }}</div>
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
@foreach($pages as $page)
|
||||||
|
<li>
|
||||||
|
@if(!empty(optional($parent)->getTranslation()->content))
|
||||||
|
<a href="{{ !empty($parent->getMeta('redirect')) ? $parent->getMeta('redirect') : route($parent->slug) }}"
|
||||||
|
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
role="menuitem">
|
||||||
|
<div class="inline-flex items-center">
|
||||||
|
<div class="mr-2">{!! $parent->getMeta('icon') !!}</div>
|
||||||
|
{{ $parent->getTranslation()->title }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@php($parent = null)
|
||||||
|
<hr class="my-2 h-0 border border-t-0 border-solid border-neutral-100 dark:border-white/10"/>
|
||||||
|
@endif
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
<button id="dropdownSub-{{ $page->id }}" data-dropdown-toggle="dropdown-{{ $page->id }}"
|
||||||
|
data-dropdown-placement="left-start" type="button"
|
||||||
|
class="flex items-center justify-between w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white">
|
||||||
|
<div class="inline-flex items-center">
|
||||||
|
<div class="mr-2">{!! $page->getMeta('icon') !!}</div>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</div>
|
||||||
|
<i class='bx bx-chevron-left'></i>
|
||||||
|
</button>
|
||||||
|
<div id="dropdown-{{ $page->id }}"
|
||||||
|
class="hidden z-50 my-4 w-48 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700">
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="dropdownSub-{{ $page->id }}">
|
||||||
|
@includeIf(Theme::moduleView('pageplus', 'elements.components.children-dropdown'), ['parent'=> $page, 'pages' => $page->childrenCached()])
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
role="menuitem">
|
||||||
|
<div class="inline-flex items-center">
|
||||||
|
<div class="mr-2">{!! $page->getMeta('icon') !!}</div>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<button id="dropdownSubNav-{{ $parent->id }}" data-dropdown-toggle="dropdown-nav-{{ $parent->id }}"
|
||||||
|
data-dropdown-placement="right-start" type="button"
|
||||||
|
class="flex items-center justify-between w-full block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white">
|
||||||
|
<div class="inline-flex items-center">
|
||||||
|
<div class="mr-2">{!! $parent->getMeta('icon') !!}</div>
|
||||||
|
{{ $parent->getTranslation()->title }}
|
||||||
|
</div>
|
||||||
|
<i class='bx bx-chevron-right'></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="dropdown-nav-{{ $parent->id }}"
|
||||||
|
class="hidden z-50 my-4 w-48 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700">
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" aria-labelledby="dropdownSubNav-{{ $parent->id }}">
|
||||||
|
@foreach($parent->childrenCached() as $page)
|
||||||
|
@if(!empty(optional($parent)->getTranslation()->content))
|
||||||
|
<a href="{{ !empty($parent->getMeta('redirect')) ? $parent->getMeta('redirect') : route($parent->slug) }}"
|
||||||
|
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
role="menuitem">
|
||||||
|
<div class="inline-flex items-center">
|
||||||
|
<div class="mr-2">{!! $parent->getMeta('icon') !!}</div>
|
||||||
|
{{ $parent->getTranslation()->title }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<hr class="my-2 h-0 border border-t-0 border-solid border-neutral-100 dark:border-white/10"/>
|
||||||
|
@php($parent = null)
|
||||||
|
@endif
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
@include(Theme::moduleView('pageplus', 'elements.components.nav-children-dropdown'), ['parent' => $page])
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
role="menuitem">
|
||||||
|
<div class="inline-flex items-center">
|
||||||
|
<div class="mr-2">{!! $page->getMeta('icon') !!}</div>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
@php($pages = pages_by_location('footer-help'))
|
||||||
|
@if(count($pages))
|
||||||
|
@foreach($pages as $page)
|
||||||
|
<li class="mb-4">
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
<button type="button" data-dropdown-toggle="pageplus-dropdown-{{ $page->id }}"
|
||||||
|
data-dropdown-placement="top"
|
||||||
|
class="hover:underline">
|
||||||
|
<span class="flex items-center">
|
||||||
|
<span class="mr-1">{!! $page->getMeta('icon') !!}</span> {{ $page->getTranslation()->title }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="z-10 hidden w-44 divide-y divide-gray-100 rounded-lg bg-white shadow dark:bg-gray-700"
|
||||||
|
style="position: absolute; inset: 0px auto auto 0px; margin: 0px; transform: translate(186px, 44px);"
|
||||||
|
data-popper-placement="right-start" id="pageplus-dropdown-{{ $page->id }}">
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" role="none">
|
||||||
|
@includeIf(Theme::moduleView('pageplus', 'elements.components.children-dropdown'), ['parent'=> $page, 'pages' => $page->childrenCached()])
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="hover:underline">
|
||||||
|
<span class="flex items-center">
|
||||||
|
{!! $page->getMeta('icon') !!}
|
||||||
|
</span>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
@php($pages = pages_by_location('footer-legal'))
|
||||||
|
@if(count($pages))
|
||||||
|
@foreach($pages as $page)
|
||||||
|
<li class="mb-4">
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
<button type="button" data-dropdown-toggle="pageplus-dropdown-{{ $page->id }}"
|
||||||
|
data-dropdown-placement="top"
|
||||||
|
class="hover:underline">
|
||||||
|
<span class="flex items-center">
|
||||||
|
<span class="mr-1">{!! $page->getMeta('icon') !!}</span> {{ $page->getTranslation()->title }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="z-10 hidden w-44 divide-y divide-gray-100 rounded-lg bg-white shadow dark:bg-gray-700"
|
||||||
|
style="position: absolute; inset: 0px auto auto 0px; margin: 0px; transform: translate(186px, 44px);"
|
||||||
|
data-popper-placement="right-start" id="pageplus-dropdown-{{ $page->id }}">
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" role="none">
|
||||||
|
@includeIf(Theme::moduleView('pageplus', 'elements.components.children-dropdown'), ['parent'=> $page, 'pages' => $page->childrenCached()])
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="hover:underline">
|
||||||
|
<span class="flex items-center">
|
||||||
|
{!! $page->getMeta('icon') !!}
|
||||||
|
</span>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
@php($pages = pages_by_location('footer-resources'))
|
||||||
|
@if(count($pages))
|
||||||
|
@foreach($pages as $page)
|
||||||
|
<li class="mb-4">
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
<button type="button" data-dropdown-toggle="pageplus-dropdown-{{ $page->id }}"
|
||||||
|
data-dropdown-placement="top"
|
||||||
|
class="hover:underline">
|
||||||
|
<span class="flex items-center">
|
||||||
|
<span class="mr-1">{!! $page->getMeta('icon') !!}</span> {{ $page->getTranslation()->title }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="z-10 hidden w-44 divide-y divide-gray-100 rounded-lg bg-white shadow dark:bg-gray-700"
|
||||||
|
style="position: absolute; inset: 0px auto auto 0px; margin: 0px; transform: translate(186px, 44px);"
|
||||||
|
data-popper-placement="right-start" id="pageplus-dropdown-{{ $page->id }}">
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" role="none">
|
||||||
|
@includeIf(Theme::moduleView('pageplus', 'elements.components.children-dropdown'), ['parent'=> $page, 'pages' => $page->childrenCached()])
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="hover:underline">
|
||||||
|
<span class="flex items-center">
|
||||||
|
{!! $page->getMeta('icon') !!}
|
||||||
|
</span>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
|
33
Resources/views/client/tailwind/elements/main-menu.blade.php
Normal file
33
Resources/views/client/tailwind/elements/main-menu.blade.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
@php($pages = pages_by_location('main-menu'))
|
||||||
|
@if(count($pages))
|
||||||
|
@foreach($pages as $page)
|
||||||
|
<li class="mr-2">
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
<button type="button" data-dropdown-toggle="pageplus-dropdown-{{ $page->id }}"
|
||||||
|
class="{{ is_active($page->slug) }} group inline-flex rounded-t-lg border-b-2 border-gray-50 px-4 py-4 text-center text-sm font-medium text-gray-500 dark:border-gray-800 dark:text-gray-400">
|
||||||
|
<span class="mr-2">
|
||||||
|
{!! $page->getMeta('icon') !!}
|
||||||
|
</span>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="z-10 hidden w-44 divide-y divide-gray-100 rounded-lg bg-white shadow dark:bg-gray-700"
|
||||||
|
style="position: absolute; inset: 0px auto auto 0px; margin: 0px; transform: translate(186px, 44px);"
|
||||||
|
data-popper-placement="right-start" id="pageplus-dropdown-{{ $page->id }}">
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" role="none">
|
||||||
|
@includeIf(Theme::moduleView('pageplus', 'elements.components.children-dropdown'), ['parent'=> $page, 'pages' => $page->childrenCached()])
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="{{ is_active($page->slug) }} group inline-flex rounded-t-lg border-b-2 border-gray-50 px-4 py-4 text-center text-sm font-medium text-gray-500 dark:border-gray-800 dark:text-gray-400">
|
||||||
|
<span class="mr-2">
|
||||||
|
{!! $page->getMeta('icon') !!}
|
||||||
|
</span>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
@php($pages = pages_by_location('navbar-dropdown-left'))
|
||||||
|
|
||||||
|
@if(count($pages))
|
||||||
|
@foreach($pages as $page)
|
||||||
|
@if(!$loop->first)
|
||||||
|
<span class="hidden w-px h-5 bg-gray-200 dark:bg-gray-600 md:inline"></span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@php($page_title = $page->getTranslation()->title)
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
<button type="button" data-dropdown-toggle="pageplus-dropdown-{{ $page->id }}"
|
||||||
|
class="mx-2 inline-flex items-center text-gray-800 dark:text-gray-300 hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-2.5 lg:px-5 py-2.5 mr-2 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-gray-800">
|
||||||
|
<div class="@empty(!$page_title) mr-2 @endempty">{!! $page->getMeta('icon') !!}</div> {{ $page_title }}
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="hidden z-50 my-4 w-48 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700"
|
||||||
|
id="pageplus-dropdown-{{ $page->id }}" data-popper-placement="bottom"
|
||||||
|
style="position: absolute; inset: 0 auto auto 0; margin: 0; transform: translate(1255px, 60px);">
|
||||||
|
<ul class="py-1" role="none">
|
||||||
|
@includeIf(Theme::moduleView('pageplus', 'elements.components.children-dropdown'), ['parent'=> $page, 'pages' => $page->childrenCached()])
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="mx-2 inline-flex items-center text-gray-800 dark:text-gray-300 hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-2.5 lg:px-5 py-2.5 mr-2 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-gray-800">
|
||||||
|
<div class="@empty(!$page_title) mr-2 @endempty">{!! $page->getMeta('icon') !!}</div> {{ $page_title }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
@if ($loop->last)
|
||||||
|
<span class="hidden mr-3 w-px h-5 bg-gray-200 dark:bg-gray-600 md:inline"></span>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
@php($pages = pages_by_location('navbar-dropdown-right'))
|
||||||
|
|
||||||
|
@if(count($pages))
|
||||||
|
@foreach($pages as $page)
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
<button type="button" data-dropdown-toggle="pageplus-dropdown-{{ $page->id }}"
|
||||||
|
class="mx-2 inline-flex items-center text-gray-800 dark:text-gray-300 hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-2.5 lg:px-5 py-2.5 mr-2 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-gray-800">
|
||||||
|
<div class="mr-2">{!! $page->getMeta('icon') !!}</div> {{ $page->getTranslation()->title }}
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="hidden z-50 my-4 w-48 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700"
|
||||||
|
id="pageplus-dropdown-{{ $page->id }}" data-popper-placement="bottom"
|
||||||
|
style="position: absolute; inset: 0 auto auto 0; margin: 0; transform: translate(1255px, 60px);">
|
||||||
|
<ul class="py-1" role="none">
|
||||||
|
@includeIf(Theme::moduleView('pageplus', 'elements.components.children-dropdown'), ['parent'=> $page, 'pages' => $page->childrenCached()])
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="mx-2 inline-flex items-center text-gray-800 dark:text-gray-300 hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-2.5 lg:px-5 py-2.5 mr-2 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-gray-800">
|
||||||
|
<div class="mr-2">{!! $page->getMeta('icon') !!}</div> {{ $page->getTranslation()->title }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
<span class="hidden w-px h-5 bg-gray-200 dark:bg-gray-600 md:inline"></span>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
@php($pages = pages_by_location('user-dropdown'))
|
||||||
|
@if(count($pages))
|
||||||
|
@foreach($pages as $page)
|
||||||
|
<li>
|
||||||
|
@if($page->childrenCached()->isNotEmpty())
|
||||||
|
<button type="button" data-dropdown-toggle="pageplus-dropdown-{{ $page->id }}"
|
||||||
|
data-dropdown-placement="right-start"
|
||||||
|
class="flex w-full items-center justify-between px-4 py-2 text-sm hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white">
|
||||||
|
<span class="flex items-center">
|
||||||
|
<span class="mr-1">{!! $page->getMeta('icon') !!}</span> {{ $page->getTranslation()->title }}
|
||||||
|
</span>
|
||||||
|
<svg aria-hidden="true" class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd"
|
||||||
|
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||||
|
clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="z-10 hidden w-44 divide-y divide-gray-100 rounded-lg bg-white shadow dark:bg-gray-700"
|
||||||
|
style="position: absolute; inset: 0px auto auto 0px; margin: 0px; transform: translate(186px, 44px);"
|
||||||
|
data-popper-placement="right-start" id="pageplus-dropdown-{{ $page->id }}">
|
||||||
|
<ul class="py-2 text-sm text-gray-700 dark:text-gray-200" role="none">
|
||||||
|
@includeIf(Theme::moduleView('pageplus', 'elements.components.children-dropdown'), ['parent'=> $page, 'pages' => $page->childrenCached()])
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($page->getMeta('redirect')) ? $page->getMeta('redirect') : route($page->slug) }}"
|
||||||
|
class="flex items-center px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white">
|
||||||
|
<span class="mr-2 text-xl text-gray-400">
|
||||||
|
{!! $page->getMeta('icon') !!}
|
||||||
|
</span>
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
|
49
Resources/views/client/tailwind/index.blade.php
Normal file
49
Resources/views/client/tailwind/index.blade.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
@extends(Theme::wrapper())
|
||||||
|
@section('title', $page->getTranslation()->title)
|
||||||
|
@section('container')
|
||||||
|
<div class="flex flex-col lg:flex-row gap-4">
|
||||||
|
@if($page->getTopmostAncestor() and $page->getTopmostAncestor()->childrenCached()->isNotEmpty())
|
||||||
|
@php($ancestor = $page->getTopmostAncestor())
|
||||||
|
<div class="lg:w-1/6 lg:flex-shrink-0">
|
||||||
|
<div class="mb-6 rounded-lg bg-white p-3 p-6 leading-6 text-gray-500 text-slate-700 shadow-xl shadow-black/5 ring-1 ring-slate-700/10 dark:bg-gray-800 dark:text-gray-400">
|
||||||
|
<a href="{{ !empty($ancestor->getMeta('redirect')) ? $ancestor->getMeta('redirect') : route($ancestor->slug) }}"
|
||||||
|
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
role="menuitem">
|
||||||
|
<div class="inline-flex items-center">
|
||||||
|
<div class="mr-2">{!! $ancestor->getMeta('icon') !!}</div>
|
||||||
|
{{ $ancestor->getTranslation()->title }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@foreach($ancestor->childrenCached() as $subpage)
|
||||||
|
@if($subpage->childrenCached()->isNotEmpty())
|
||||||
|
@include(Theme::moduleView('pageplus', 'elements.components.nav-children-dropdown'), ['parent' => $subpage])
|
||||||
|
@else
|
||||||
|
<a href="{{ !empty($subpage->getMeta('redirect')) ? $subpage->getMeta('redirect') : route($subpage->slug) }}"
|
||||||
|
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||||
|
role="menuitem">
|
||||||
|
<div class="inline-flex items-center">
|
||||||
|
<div class="mr-2">{!! $subpage->getMeta('icon') !!}</div>
|
||||||
|
{{ $subpage->getTranslation()->title }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="w-full min-h-screen">
|
||||||
|
<div class="mb-6 rounded-lg bg-white p-3 p-6 leading-6 text-gray-500 text-slate-700 shadow-xl shadow-black/5 ring-1 ring-slate-700/10 dark:bg-gray-800 dark:text-gray-400">
|
||||||
|
<div class="text-center text-gray-500 dark:text-gray-400">
|
||||||
|
<h1 class="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
|
||||||
|
{{ $page->getTranslation()->title }}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dark:bg-gray-800 rounded-lg text-gray-500 dark:text-gray-400 p-4">
|
||||||
|
{!! $page->getTranslation()->content !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
17
Routes/admin.php
Normal file
17
Routes/admin.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Modules\PagePlus\Http\Controllers\AdminPagePlusController;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
Route::prefix('pageplus')->group(function() {
|
||||||
|
Route::get('/', [AdminPagePlusController::class, 'index'])->name('admin.pageplus.index');
|
||||||
|
Route::get('/create', [AdminPagePlusController::class, 'create'])->name('admin.pageplus.create');
|
||||||
|
Route::post('/store', [AdminPagePlusController::class, 'store'])->name('admin.pageplus.store');
|
||||||
|
Route::get('/edit/{page}', [AdminPagePlusController::class, 'create'])->name('admin.pageplus.edit');
|
||||||
|
Route::get('/destroy/{page}', [AdminPagePlusController::class, 'destroy'])->name('admin.pageplus.delete');
|
||||||
|
Route::get('/translate/{page}/{locale?}', [AdminPagePlusController::class, 'translate'])
|
||||||
|
->defaults('locale', app()->getLocale())
|
||||||
|
->name('admin.pageplus.translate');
|
||||||
|
Route::post('/translate/{page}', [AdminPagePlusController::class, 'translateStore'])->name('admin.pageplus.translate.store');
|
||||||
|
Route::get('/change-order/{page}/{action?}', [AdminPagePlusController::class, 'changeOrder'])->name('admin.pageplus.change_order');
|
||||||
|
});
|
8
Routes/web.php
Normal file
8
Routes/web.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Modules\PagePlus\Entities\PageHelper;
|
||||||
|
|
||||||
|
|
||||||
|
PageHelper::registerRoutes();
|
||||||
|
|
||||||
|
|
47
Rules/UniqueSlug.php
Normal file
47
Rules/UniqueSlug.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\PagePlus\Rules;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Validation\Rule;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Modules\PagePlus\Entities\PagePlus;
|
||||||
|
|
||||||
|
class UniqueSlug implements Rule
|
||||||
|
{
|
||||||
|
protected mixed $ignoreId;
|
||||||
|
|
||||||
|
public function __construct($ignoreId = null)
|
||||||
|
{
|
||||||
|
$this->ignoreId = $ignoreId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function passes($attribute, $value): bool
|
||||||
|
{
|
||||||
|
// Check if the slug already exists and does not belong to the current record
|
||||||
|
$existingPage = PagePlus::where('slug', $value)->first();
|
||||||
|
if ($existingPage && $this->ignoreId && $existingPage->id == $this->ignoreId) {
|
||||||
|
// If the slug already exists, but it belongs to the current record, ignore the uniqueness check
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all routes and check against static URIss
|
||||||
|
foreach (Route::getRoutes() as $route) {
|
||||||
|
$uriSegments = explode('/', $route->uri());
|
||||||
|
$firstSegment = $uriSegments[0] ?? null; // Get the first segment of the URI
|
||||||
|
|
||||||
|
// Remove any dynamic segments from the first segment
|
||||||
|
if ($firstSegment && !Str::startsWith($firstSegment, '{')) {
|
||||||
|
if ($firstSegment === $value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function message(): string
|
||||||
|
{
|
||||||
|
return 'The :attribute is already in use.';
|
||||||
|
}
|
||||||
|
}
|
23
composer.json
Normal file
23
composer.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "nwidart/pageplus",
|
||||||
|
"description": "",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "GIGABAIT",
|
||||||
|
"email": "xgigabaitx@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"providers": [],
|
||||||
|
"aliases": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Modules\\PagePlus\\": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
helper.php
Normal file
18
helper.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Modules\PagePlus\Entities\PageHelper;
|
||||||
|
use Modules\PagePlus\Entities\PagePlus;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
|
if (!function_exists('pages_by_location')) {
|
||||||
|
function pages_by_location($location = null)
|
||||||
|
{
|
||||||
|
return Cache::rememberForever(PageHelper::cacheKey('byLocation', $location), function () use ($location) {
|
||||||
|
$pages = PagePlus::whereNull('parent_id')->get();
|
||||||
|
return $pages->filter(function ($page) use ($location) {
|
||||||
|
return $page->getMeta('location') == $location;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
11
module.json
Normal file
11
module.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "PagePlus",
|
||||||
|
"alias": "pageplus",
|
||||||
|
"description": "",
|
||||||
|
"keywords": [],
|
||||||
|
"priority": 0,
|
||||||
|
"providers": [
|
||||||
|
"Modules\\PagePlus\\Providers\\PagePlusServiceProvider"
|
||||||
|
],
|
||||||
|
"files": ["helper.php"]
|
||||||
|
}
|
3
package.json
Normal file
3
package.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"private": true
|
||||||
|
}
|
Loading…
Reference in a new issue