Page Plus

Changed the text editor
This commit is contained in:
ShadowVirtual 2024-04-01 03:51:52 -08:00
parent ce1fe12b94
commit e003ffa38a
37 changed files with 1443 additions and 0 deletions

24
Config/config.php Normal file
View 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' => '',
],
],
],
];

View file

@ -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');
}
};

View file

@ -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');
}
};

View file

@ -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
View 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
View 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
View 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);
});
}
}

View 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);
});
}
}

View 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'));
}
}

View 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'));
}
}

View 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;
}
}

View 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'));
}
}

View 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.',
];

View 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' => 'Порядок успішно змінено.',
];

View 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">&times;</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

View 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')

View 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

View 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

View 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

View 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

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View 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
View 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
View file

@ -0,0 +1,8 @@
<?php
use Modules\PagePlus\Entities\PageHelper;
PageHelper::registerRoutes();

47
Rules/UniqueSlug.php Normal file
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,3 @@
{
"private": true
}