Testing Alpha
This commit is contained in:
20
resources/views/audit/laravel-logs/index.blade.php
Normal file
20
resources/views/audit/laravel-logs/index.blade.php
Normal file
@ -0,0 +1,20 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Eventos de auditoría de sistema')
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@push('page-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js',
|
||||
])
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('vuexy-admin::security-events-table')
|
||||
@endsection
|
20
resources/views/audit/security-events/index.blade.php
Normal file
20
resources/views/audit/security-events/index.blade.php
Normal file
@ -0,0 +1,20 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Eventos de auditoría de sistema')
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@push('page-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js',
|
||||
])
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('vuexy-admin::security-events-table')
|
||||
@endsection
|
20
resources/views/audit/users-auth-logs/index.blade.php
Normal file
20
resources/views/audit/users-auth-logs/index.blade.php
Normal file
@ -0,0 +1,20 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Registros de accesos al sistema')
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@push('page-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js',
|
||||
])
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('vuexy-admin::auth-users-logs-table')
|
||||
@endsection
|
@ -5,7 +5,7 @@
|
||||
$configData = Helper::appClasses();
|
||||
@endphp
|
||||
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
@extends('vuexy-admin::layouts.vuexy.blankLayout')
|
||||
|
||||
@section('title', 'Iniciar sesión')
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
$configData = Helper::appClasses();
|
||||
@endphp
|
||||
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
@extends('vuexy-admin::layouts.vuexy.blankLayout')
|
||||
|
||||
@section('title', 'Iniciar sesión')
|
||||
|
||||
|
@ -1,41 +0,0 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Ajustes de caché')
|
||||
|
||||
@push('page-script')
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/js/pages/cache-manager-scripts.js')
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="mb-6">
|
||||
@livewire('vuexy-admin::cache-stats')
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
@livewire('vuexy-admin::session-stats')
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="mb-6">
|
||||
@livewire('vuexy-admin::cache-functions')
|
||||
</div>
|
||||
<div class="row">
|
||||
@if($configCache['redisInUse'])
|
||||
<div class="col-md-6">
|
||||
<div class="mb-6">
|
||||
@livewire('vuexy-admin::redis-stats')
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($configCache['memcachedInUse'])
|
||||
<div class="col-md-6">
|
||||
<div class="mb-6">
|
||||
@livewire('vuexy-admin::memcached-stats')
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
0
resources/views/components/badge/dynamic.blade.php
Normal file
0
resources/views/components/badge/dynamic.blade.php
Normal file
27
resources/views/components/button/form-buttons.blade.php
Normal file
27
resources/views/components/button/form-buttons.blade.php
Normal file
@ -0,0 +1,27 @@
|
||||
@props([
|
||||
'label' => '',
|
||||
'mode' => 'create',
|
||||
])
|
||||
|
||||
@php
|
||||
$btnLabel = match($mode) {
|
||||
'create' => 'Crear ' . $label,
|
||||
'edit' => 'Guardar cambios',
|
||||
'delete' => 'Eliminar'
|
||||
};
|
||||
|
||||
$btnType = match($mode) {
|
||||
'create' => 'success',
|
||||
'edit' => 'warning',
|
||||
'delete' => 'danger'
|
||||
};
|
||||
|
||||
@endphp
|
||||
|
||||
<div class="pt-3">
|
||||
<button type="submit" class="btn btn-{{ $btnType }} btn-submit waves-effect waves mr-3 mb-3">{{ $btnLabel }}</button>
|
||||
<button type="reset" class="btn btn-reset mr-3 mb-3">Cancelar</button>
|
||||
</div>
|
||||
@if($mode == 'delete')
|
||||
<x-vuexy-admin::form.checkbox model="confirmDeletion" label="Confirmar eliminación" parentClass="confirm-deletion" data-always-enabled switch switch-type="square" color="danger" size="lg" with-icon />
|
||||
@endif
|
0
resources/views/components/card/stats.blade.php
Normal file
0
resources/views/components/card/stats.blade.php
Normal file
111
resources/views/components/development/model-debug.blade.php
Normal file
111
resources/views/components/development/model-debug.blade.php
Normal file
@ -0,0 +1,111 @@
|
||||
<div class="p-6 space-y-6">
|
||||
<div class="text-xl font-semibold text-gray-800">
|
||||
🧪 Diagnóstico del modelo <code>{{ get_class($model) }}</code>
|
||||
</div>
|
||||
|
||||
@php
|
||||
$debug = method_exists($model, 'getExtendableDebugData') ? $model->getExtendableDebugData() : [];
|
||||
|
||||
$attributes = $debug['attributes'] ?? [];
|
||||
$traits = $debug['traits'] ?? [];
|
||||
$methods = [];
|
||||
|
||||
$methodTypes = ['fillable', 'cast', 'audit', 'hidden', 'appends'];
|
||||
|
||||
foreach ($traits as $trait) {
|
||||
$traitName = class_basename($trait);
|
||||
foreach ($methodTypes as $type) {
|
||||
$method = 'get' . ucfirst($type) . $traitName;
|
||||
if (method_exists($model, $method)) {
|
||||
try {
|
||||
$methods[$traitName][$type] = $model->{$method}();
|
||||
} catch (\Throwable $e) {
|
||||
$methods[$traitName][$type] = ['⚠️ Error: ' . $e->getMessage()];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$simpleProps = [
|
||||
'hidden' => method_exists($model, 'getHidden') ? $model->getHidden() : ($model->hidden ?? []),
|
||||
'appends' => method_exists($model, 'getAppends') ? $model->getAppends() : ($model->appends ?? []),
|
||||
];
|
||||
@endphp
|
||||
|
||||
{{-- GRUPO: Atributos Extendidos --}}
|
||||
<div class="bg-white border rounded-xl shadow-sm">
|
||||
<div class="px-5 py-4 border-b bg-gradient-to-r from-gray-100 to-gray-50 rounded-t-xl">
|
||||
<h2 class="text-lg font-semibold text-gray-700">📦 Atributos extendidos del modelo</h2>
|
||||
</div>
|
||||
<div class="p-5 space-y-6">
|
||||
@foreach ($attributes as $type => $data)
|
||||
<div>
|
||||
<h3 class="text-md font-semibold text-gray-800 uppercase tracking-wide mb-2">
|
||||
{{ $type }}
|
||||
<span class="text-xs text-gray-500">({{ $data['cache_key'] ?? 'sin cache' }})</span>
|
||||
</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm text-gray-600">
|
||||
<div>
|
||||
<p class="font-semibold text-gray-700 mb-1">Base</p>
|
||||
<pre class="bg-gray-100 p-2 rounded text-xs">@json($data['base'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)</pre>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-gray-700 mb-1">Extendidos</p>
|
||||
<pre class="bg-gray-100 p-2 rounded text-xs">@json($data['extended'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)</pre>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-gray-700 mb-1">Combinado</p>
|
||||
<pre class="bg-gray-100 p-2 rounded text-xs">@json($data['combined'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-4 mt-3 text-xs text-gray-500">
|
||||
<span>🚀 Cache: <strong class="{{ $data['cache_enabled'] ? 'text-green-600' : 'text-red-600' }}">{{ $data['cache_enabled'] ? 'ACTIVO' : 'INACTIVO' }}</strong></span>
|
||||
<span>🧪 Bypass: <strong class="{{ $data['bypass_cache'] ? 'text-yellow-600' : 'text-gray-600' }}">{{ $data['bypass_cache'] ? 'Sí (modo local)' : 'No' }}</strong></span>
|
||||
<span>⏱ TTL: {{ $data['ttl'] }} seg</span>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- GRUPO: hidden y appends --}}
|
||||
<div class="bg-white border rounded-xl shadow-sm">
|
||||
<div class="px-5 py-4 border-b bg-gradient-to-r from-gray-100 to-gray-50 rounded-t-xl">
|
||||
<h2 class="text-lg font-semibold text-gray-700">🔐 Propiedades visibles y ocultas</h2>
|
||||
</div>
|
||||
<div class="p-5 grid grid-cols-1 md:grid-cols-2 gap-6 text-sm text-gray-700">
|
||||
@foreach($simpleProps as $key => $value)
|
||||
<div>
|
||||
<h3 class="font-semibold mb-2 capitalize">{{ $key }}</h3>
|
||||
<pre class="bg-gray-100 p-2 rounded text-xs">@json($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)</pre>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- GRUPO: Traits --}}
|
||||
<div class="bg-white border rounded-xl shadow-sm">
|
||||
<div class="px-5 py-4 border-b bg-gradient-to-r from-gray-100 to-gray-50 rounded-t-xl">
|
||||
<h2 class="text-lg font-semibold text-gray-700">🧠 Traits detectados</h2>
|
||||
</div>
|
||||
<div class="p-5">
|
||||
<ul class="text-sm text-gray-700 list-disc pl-5 space-y-1">
|
||||
@foreach($traits as $trait)
|
||||
<li><code class="text-indigo-600">{{ $trait }}</code></li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- GRUPO: Métodos por Trait --}}
|
||||
<div class="bg-white border rounded-xl shadow-sm">
|
||||
<div class="px-5 py-4 border-b bg-gradient-to-r from-gray-100 to-gray-50 rounded-t-xl">
|
||||
<h2 class="text-lg font-semibold text-gray-700">🔍 Métodos de extensión encontrados</h2>
|
||||
</div>
|
||||
<div class="p-5">
|
||||
<pre class="bg-gray-100 p-3 rounded text-xs text-gray-700">@json($methods, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,6 +1,6 @@
|
||||
@props([
|
||||
'id' => uniqid(), // ID único del formulario
|
||||
'uniqueId' => '', // ID único del formulario
|
||||
'uid' => '', // ID único del formulario
|
||||
'mode' => 'create', // Modo actual ('create', 'edit', 'delete')
|
||||
'method' => 'POST', // Método del formulario (POST, GET, PUT, DELETE)
|
||||
'action' => '', // URL de acción
|
||||
@ -31,10 +31,10 @@
|
||||
|
||||
<form {{ $attributes->merge($formAttributes) }}>
|
||||
@if (!$whitOutId)
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" type="hidden" model="id" />
|
||||
<x-vuexy-admin::form.input :uid="$uid" type="hidden" model="id" />
|
||||
@endif
|
||||
@if (!$whitOutMode)
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" type="hidden" model="mode" />
|
||||
<x-vuexy-admin::form.input :uid="$uid" type="hidden" model="mode" />
|
||||
@endif
|
||||
@if ($mode !== 'delete' && in_array($actionPosition, ['top', 'both']))
|
||||
<div class="notification-container mb-4"></div>
|
||||
|
81
resources/views/components/form/input-password.blade.php
Normal file
81
resources/views/components/form/input-password.blade.php
Normal file
@ -0,0 +1,81 @@
|
||||
@props([
|
||||
'uid' => uniqid(),
|
||||
'model' => '',
|
||||
'label' => 'Contraseña',
|
||||
'placeholder' => '············',
|
||||
'labelClass' => '',
|
||||
'icon' => null,
|
||||
])
|
||||
|
||||
@php
|
||||
$livewireModel = $attributes->get('wire:model', $model);
|
||||
$name = $attributes->get('name', $livewireModel);
|
||||
$inputId = $attributes->get('id', $name . '_' . $uid);
|
||||
|
||||
$errorKey = $livewireModel ?: $name;
|
||||
$hasError = $errors->has($errorKey);
|
||||
$errorClass = $hasError ? 'is-invalid' : '';
|
||||
@endphp
|
||||
|
||||
<div class="mb-4 fv-row">
|
||||
<label class="form-label {{ $labelClass }}" for="{{ $inputId }}">{{ $label }}</label>
|
||||
|
||||
<div class="input-group input-group-merge">
|
||||
{{-- Prefijo (opcional) --}}
|
||||
@if ($icon)
|
||||
<span class="input-group-text">
|
||||
<i class="{{ $icon }}"></i>
|
||||
</span>
|
||||
@endif
|
||||
|
||||
{{-- Input --}}
|
||||
<input
|
||||
type="password"
|
||||
id="{{ $inputId }}"
|
||||
name="{{ $name }}"
|
||||
wire:model="{{ $livewireModel }}"
|
||||
class="form-control {{ $errorClass }}"
|
||||
placeholder="{{ $placeholder }}"
|
||||
autocomplete="new-password"
|
||||
aria-describedby="{{ $inputId }}-aria"
|
||||
/>
|
||||
|
||||
{{-- Toggle --}}
|
||||
<span class="input-group-text cursor-pointer toggle-password" data-target="{{ $inputId }}">
|
||||
<i class="ti ti-eye-off password-toggle-icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
@if ($hasError)
|
||||
<span class="text-danger">{{ $errors->first($errorKey) }}</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
function attachPasswordToggles() {
|
||||
document.querySelectorAll('.toggle-password').forEach(toggle => {
|
||||
const alreadyAttached = toggle.getAttribute('data-bound');
|
||||
if (alreadyAttached) return;
|
||||
|
||||
toggle.setAttribute('data-bound', 'true');
|
||||
|
||||
toggle.addEventListener('click', function () {
|
||||
const targetId = this.getAttribute('data-target');
|
||||
const input = document.getElementById(targetId);
|
||||
const icon = this.querySelector('.password-toggle-icon');
|
||||
|
||||
if (input && icon) {
|
||||
const isPassword = input.type === 'password';
|
||||
input.type = isPassword ? 'text' : 'password';
|
||||
icon.classList.toggle('ti-eye', isPassword);
|
||||
icon.classList.toggle('ti-eye-off', !isPassword);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
attachPasswordToggles();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -146,14 +146,14 @@
|
||||
{{-- Prefijo --}}
|
||||
@if ($prefix || $prefixIcon)
|
||||
@if ($prefixClickable)
|
||||
<button type="button" class="input-group-text cursor-pointer" {{ $prefixAction ? "wire:click=$prefixAction" : '' }}>
|
||||
<span class="input-group-text cursor-pointer" {{ $prefixAction ? "wire:click=$prefixAction" : '' }}>
|
||||
@if ($prefixIcon)
|
||||
<i class="{{ $prefixIcon }}"></i>
|
||||
@endif
|
||||
@if ($prefix)
|
||||
{{ $prefix }}
|
||||
@endif
|
||||
</button>
|
||||
</span>
|
||||
@else
|
||||
<span class="input-group-text">
|
||||
@if ($prefixIcon)
|
||||
@ -171,14 +171,14 @@
|
||||
{{-- Sufijo --}}
|
||||
@if ($suffix || $suffixIcon)
|
||||
@if ($suffixClickable)
|
||||
<button type="button" class="input-group-text cursor-pointer" {{ $suffixAction ? "wire:click=$suffixAction" : '' }}>
|
||||
<span class="input-group-text cursor-pointer" {{ $suffixAction ? "wire:click=$suffixAction" : '' }}>
|
||||
@if ($suffixIcon)
|
||||
<i class="{{ $suffixIcon }}"></i>
|
||||
@endif
|
||||
@if ($suffix)
|
||||
{{ $suffix }}
|
||||
@endif
|
||||
</button>
|
||||
</span>
|
||||
@else
|
||||
<span class="input-group-text">
|
||||
@if ($suffixIcon)
|
||||
|
0
resources/views/components/panel/body.blade.php
Normal file
0
resources/views/components/panel/body.blade.php
Normal file
0
resources/views/components/panel/header.blade.php
Normal file
0
resources/views/components/panel/header.blade.php
Normal file
0
resources/views/components/panel/wrapper.blade.php
Normal file
0
resources/views/components/panel/wrapper.blade.php
Normal file
@ -6,13 +6,13 @@
|
||||
'id' => uniqid(),
|
||||
'tagName' => '',
|
||||
'datatableConfig' => [],
|
||||
'routes' => [],
|
||||
'noFilterButtons' => false
|
||||
])
|
||||
|
||||
@php
|
||||
if($tagName)
|
||||
if($tagName){
|
||||
$id = 'bt-' . Str::kebab($tagName) . 's';
|
||||
}
|
||||
@endphp
|
||||
|
||||
<div id="{{ $id }}" wire:ignore>
|
||||
@ -58,9 +58,9 @@
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@isset($routes)
|
||||
@isset($datatableConfig['routes'])
|
||||
<script id="app-routes" type="application/json">
|
||||
{!! json_encode($routes) !!}
|
||||
{!! json_encode($datatableConfig['routes']) !!}
|
||||
</script>
|
||||
@endisset
|
||||
@endpush
|
||||
|
0
resources/views/components/ui/tabs/pills.blade.php
Normal file
0
resources/views/components/ui/tabs/pills.blade.php
Normal file
48
resources/views/components/user/details/___panel.blade.php
Normal file
48
resources/views/components/user/details/___panel.blade.php
Normal file
@ -0,0 +1,48 @@
|
||||
<!-- resources/views/components/user/details/panel.blade.php -->
|
||||
@props([
|
||||
'user' => null,
|
||||
'tabs' => [],
|
||||
'stats' => [],
|
||||
'timeline' => [],
|
||||
'connections' => [],
|
||||
'teams' => [],
|
||||
])
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<!-- Banner y Header -->
|
||||
<x-vuexy-admin::user.details.banner-profile-header
|
||||
:banner-url="$user?->banner_url"
|
||||
:avatar-url="$user?->profile_photo_url"
|
||||
:name="$user?->name"
|
||||
:position="$user?->position"
|
||||
:location="$user?->location"
|
||||
:joined="$user?->joined_at?->format('F Y')"
|
||||
button-label="Connected"
|
||||
button-icon="ti ti-user-check"
|
||||
/>
|
||||
|
||||
<!-- Tabs -->
|
||||
<x-vuexy-admin::user.details.tabs :tabs="$tabs" />
|
||||
|
||||
<!-- Contenido Principal -->
|
||||
<div class="row">
|
||||
<!-- Columna Izquierda -->
|
||||
<div class="col-xl-4 col-lg-5 col-md-5">
|
||||
<x-vuexy-admin::user.details.about :user="$user" class="mb-6" />
|
||||
<x-vuexy-admin::user.details.overview :stats="$stats" />
|
||||
</div>
|
||||
|
||||
<!-- Columna Derecha -->
|
||||
<div class="col-xl-8 col-lg-7 col-md-7">
|
||||
<x-vuexy-admin::user.details.timeline :items="$timeline" class="mb-6" />
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-xl-6">
|
||||
<x-vuexy-admin::user.details.connections :connections="$connections" />
|
||||
</div>
|
||||
<div class="col-lg-12 col-xl-6">
|
||||
<x-vuexy-admin::user.details.teams :teams="$teams" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
111
resources/views/components/user/details/about.blade.php
Normal file
111
resources/views/components/user/details/about.blade.php
Normal file
@ -0,0 +1,111 @@
|
||||
@props(['user'])
|
||||
|
||||
@php
|
||||
$locale = app()->getLocale();
|
||||
$roles = $user->roles ?? collect();
|
||||
$flags = $user->getRegisteredFlags() ?? [];
|
||||
@endphp
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
|
||||
{{-- SECCIÓN: DATOS PERSONALES --}}
|
||||
<small class="text-uppercase text-muted">Información</small>
|
||||
<ul class="list-unstyled my-3 py-1">
|
||||
<li class="d-flex align-items-center mb-3">
|
||||
<i class="ti ti-user ti-lg me-2 text-muted"></i>
|
||||
<span class="fw-medium me-1">Nombre:</span>
|
||||
<span>{{ $user->full_name ?? 'N/A' }}</span>
|
||||
</li>
|
||||
<li class="d-flex align-items-center mb-3">
|
||||
<i class="ti ti-check ti-lg me-2 text-muted"></i>
|
||||
<span class="fw-medium me-1">Estado:</span>
|
||||
<span>{{ $user->status_label ?? 'Sin estado' }}</span>
|
||||
</li>
|
||||
<li class="d-flex align-items-start mb-3">
|
||||
<i class="ti ti-shield ti-lg me-2 text-muted"></i>
|
||||
<div>
|
||||
<small class="card-text text-uppercase text-muted small">Roles</small>
|
||||
<ul class="list-unstyled my-3 py-1 d-flex flex-wrap gap-2">
|
||||
@foreach($user->roles as $role)
|
||||
@php
|
||||
$meta = json_decode($role->ui_metadata, true) ?? [];
|
||||
$icon = $meta['icon'] ?? 'ti ti-user';
|
||||
$style = $meta['style'] ?? 'primary'; // default badge style
|
||||
$description = $meta['description'][app()->getLocale()] ?? $role->name;
|
||||
@endphp
|
||||
<li>
|
||||
<span class="badge bg-label-{{ $style }} d-inline-flex align-items-center gap-1"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="{{ $description }}">
|
||||
<i class="{{ $icon }} mr-1"></i> {{ $role->name }}
|
||||
</span>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
@if(!empty($flags))
|
||||
<li class="d-flex align-items-start mb-3">
|
||||
<i class="ti ti-flag ti-lg me-2 text-muted"></i>
|
||||
<div>
|
||||
<div class="fw-medium">Flags:</div>
|
||||
<span class="text-muted">{{ implode(', ', array_keys($flags)) }}</span>
|
||||
</div>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
|
||||
{{-- SECCIÓN: CONTACTO --}}
|
||||
<small class="text-uppercase text-muted">Contacto</small>
|
||||
<ul class="list-unstyled my-3 py-1">
|
||||
<li class="d-flex align-items-center mb-3">
|
||||
<i class="ti ti-mail ti-lg me-2 text-muted"></i>
|
||||
<span class="fw-medium me-1">Email:</span>
|
||||
<span>{{ $user->email }}</span>
|
||||
</li>
|
||||
<li class="d-flex align-items-center mb-3">
|
||||
<i class="ti ti-phone ti-lg me-2 text-muted"></i>
|
||||
<span class="fw-medium me-1">Teléfono:</span>
|
||||
<span>{{ $user->phone ?? 'No registrado' }}</span>
|
||||
</li>
|
||||
<li class="d-flex align-items-center mb-3">
|
||||
<i class="ti ti-brand-skype ti-lg me-2 text-muted"></i>
|
||||
<span class="fw-medium me-1">Skype:</span>
|
||||
<span>{{ $user->skype ?? 'No registrado' }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{-- SECCIÓN: OTROS --}}
|
||||
<small class="text-uppercase text-muted">Otros</small>
|
||||
<ul class="list-unstyled mt-3 pt-1">
|
||||
<li class="d-flex align-items-center mb-3">
|
||||
<i class="ti ti-world ti-lg me-2 text-muted"></i>
|
||||
<span class="fw-medium me-1">País:</span>
|
||||
<span>{{ $user->country ?? 'No disponible' }}</span>
|
||||
</li>
|
||||
<li class="d-flex align-items-center mb-3">
|
||||
<i class="ti ti-language ti-lg me-2 text-muted"></i>
|
||||
<span class="fw-medium me-1">Idioma(s):</span>
|
||||
<span>{{ $user->languages ?? 'Español' }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{-- SECCIÓN: EQUIPOS --}}
|
||||
@if(!empty($user->teams))
|
||||
<small class="text-uppercase text-muted">Equipos</small>
|
||||
<ul class="list-unstyled mt-3 pt-1">
|
||||
@forelse($user->teams as $team)
|
||||
<li class="d-flex align-items-center mb-2">
|
||||
<i class="ti ti-users me-2 text-muted"></i>
|
||||
<span class="fw-medium me-1">{{ $team['name'] }}</span>
|
||||
<span class="text-muted">({{ $team['members'] }} miembros)</span>
|
||||
</li>
|
||||
@empty
|
||||
<li class="text-muted">Sin equipos asignados</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,117 @@
|
||||
@props([
|
||||
'bannerUrl' => null,
|
||||
'avatarUrl' => null,
|
||||
'name' => 'Nombre no definido',
|
||||
'position' => null,
|
||||
'location' => null,
|
||||
'joined' => null,
|
||||
'buttonLabel' => null,
|
||||
'buttonIcon' => null,
|
||||
'buttonClass' => 'btn btn-primary mb-1 waves-effect waves-light',
|
||||
'buttonAction' => 'javascript:void(0)'
|
||||
])
|
||||
|
||||
<div class="card mb-6">
|
||||
{{-- Banner superior --}}
|
||||
<div class="user-profile-header-banner">
|
||||
@if ($bannerUrl)
|
||||
<img src="{{ $bannerUrl }}" alt="Banner image" class="rounded-top">
|
||||
@else
|
||||
<div class="bg-secondary rounded-top" style="height: 200px;"></div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Contenido principal del perfil --}}
|
||||
<div class="user-profile-header d-flex flex-column flex-lg-row text-sm-start text-center mb-5">
|
||||
<div class="flex-shrink-0 mt-n2 mx-sm-0 mx-auto">
|
||||
<img src="{{ $avatarUrl }}" alt="user image" class="d-block h-auto ms-0 ms-sm-6 rounded user-profile-img">
|
||||
</div>
|
||||
<div class="flex-grow-1 mt-3 mt-lg-5">
|
||||
<div class="d-flex align-items-md-end align-items-sm-start align-items-center justify-content-md-between justify-content-start mx-5 flex-md-row flex-column gap-4">
|
||||
<div class="user-profile-info">
|
||||
<h4 class="mb-2 mt-lg-6">{{ $name }}</h4>
|
||||
<ul class="list-inline mb-0 d-flex align-items-center flex-wrap justify-content-sm-start justify-content-center gap-4 my-2">
|
||||
@if ($position)
|
||||
<li class="list-inline-item d-flex gap-2 align-items-center">
|
||||
<i class="ti ti-palette ti-lg"></i><span class="fw-medium">{{ $position }}</span>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
@if ($location)
|
||||
<li class="list-inline-item d-flex gap-2 align-items-center">
|
||||
<i class="ti ti-map-pin ti-lg"></i><span class="fw-medium">{{ $location }}</span>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
@if ($joined)
|
||||
<li class="list-inline-item d-flex gap-2 align-items-center">
|
||||
<i class="ti ti-calendar ti-lg"></i><span class="fw-medium">Joined {{ $joined }}</span>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@if ($buttonLabel)
|
||||
<a href="{{ $buttonAction }}" class="{{ $buttonClass }}">
|
||||
@if ($buttonIcon)
|
||||
<i class="{{ $buttonIcon }} ti-xs me-2"></i>
|
||||
@endif
|
||||
{{ $buttonLabel }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
<div class="card mb-6">
|
||||
|
||||
|
||||
|
||||
<div class="user-profile-header-banner">
|
||||
<img src="http://vuexy-vite.test/assets/img/pages/profile-banner.png" alt="Banner image" class="rounded-top">
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="user-profile-header d-flex flex-column flex-lg-row text-sm-start text-center mb-5">
|
||||
|
||||
|
||||
<div class="flex-shrink-0 mt-n2 mx-sm-0 mx-auto">
|
||||
<img src="http://vuexy-vite.test/assets/img/avatars/1.png" alt="user image" class="d-block h-auto ms-0 ms-sm-6 rounded user-profile-img">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex-grow-1 mt-3 mt-lg-5">
|
||||
<div class="d-flex align-items-md-end align-items-sm-start align-items-center justify-content-md-between justify-content-start mx-5 flex-md-row flex-column gap-4">
|
||||
<div class="user-profile-info">
|
||||
<h4 class="mb-2 mt-lg-6">John Doe</h4>
|
||||
<ul class="list-inline mb-0 d-flex align-items-center flex-wrap justify-content-sm-start justify-content-center gap-4 my-2">
|
||||
<li class="list-inline-item d-flex gap-2 align-items-center">
|
||||
<i class="ti ti-palette ti-lg"></i><span class="fw-medium">UX Designer</span>
|
||||
</li>
|
||||
<li class="list-inline-item d-flex gap-2 align-items-center">
|
||||
<i class="ti ti-map-pin ti-lg"></i><span class="fw-medium">Vatican City</span>
|
||||
</li>
|
||||
<li class="list-inline-item d-flex gap-2 align-items-center">
|
||||
<i class="ti ti-calendar ti-lg"></i><span class="fw-medium"> Joined April 2021</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a href="javascript:void(0)" class="btn btn-primary mb-1 waves-effect waves-light">
|
||||
<i class="ti ti-user-check ti-xs me-2"></i>Connected
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
-->
|
@ -0,0 +1,56 @@
|
||||
<!-- resources/views/components/user/details/connections.blade.php -->
|
||||
@props([
|
||||
'connections' => [
|
||||
['avatar' => 'assets/img/avatars/2.png', 'name' => 'Cecilia Payne', 'count' => '45', 'connected' => true],
|
||||
['avatar' => 'assets/img/avatars/3.png', 'name' => 'Curtis Fletcher', 'count' => '1.32k', 'connected' => false],
|
||||
['avatar' => 'assets/img/avatars/10.png', 'name' => 'Alice Stone', 'count' => '125', 'connected' => false],
|
||||
['avatar' => 'assets/img/avatars/7.png', 'name' => 'Darrell Barnes', 'count' => '456', 'connected' => true],
|
||||
['avatar' => 'assets/img/avatars/12.png', 'name' => 'Eugenia Moore', 'count' => '1.2k', 'connected' => true],
|
||||
]
|
||||
])
|
||||
|
||||
<div class="card card-action mb-6">
|
||||
<div class="card-header align-items-center">
|
||||
<h5 class="card-action-title mb-0">Connections</h5>
|
||||
<div class="card-action-element">
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0 text-muted waves-effect waves-light" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="ti ti-dots-vertical ti-md text-muted"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item waves-effect" href="#">Share connections</a></li>
|
||||
<li><a class="dropdown-item waves-effect" href="#">Suggest edits</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item waves-effect" href="#">Report bug</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled mb-0">
|
||||
@foreach ($connections as $connection)
|
||||
<li class="mb-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar me-2">
|
||||
<img src="{{ asset($connection['avatar']) }}" alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div class="me-2">
|
||||
<h6 class="mb-0">{{ $connection['name'] }}</h6>
|
||||
<small>{{ $connection['count'] }} Connections</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
<button class="btn {{ $connection['connected'] ? 'btn-label-primary' : 'btn-primary' }} btn-icon waves-effect waves-light">
|
||||
<i class="ti {{ $connection['connected'] ? 'ti-user-check' : 'ti-user-x' }} ti-md"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
<li class="text-center">
|
||||
<a href="javascript:void(0);">View all connections</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
24
resources/views/components/user/details/overview.blade.php
Normal file
24
resources/views/components/user/details/overview.blade.php
Normal file
@ -0,0 +1,24 @@
|
||||
<!-- resources/views/components/user/details/overview.blade.php -->
|
||||
|
||||
<div class="card mb-6">
|
||||
<div class="card-body">
|
||||
<small class="card-text text-uppercase text-muted small">Overview</small>
|
||||
<ul class="list-unstyled mb-0 mt-3 pt-1">
|
||||
<li class="d-flex align-items-end mb-4">
|
||||
<i class="ti ti-check ti-lg"></i>
|
||||
<span class="fw-medium mx-2">Task Compiled:</span>
|
||||
<span>{{ $tasksCompiled ?? '13.5k' }}</span>
|
||||
</li>
|
||||
<li class="d-flex align-items-end mb-4">
|
||||
<i class="ti ti-layout-grid ti-lg"></i>
|
||||
<span class="fw-medium mx-2">Projects Compiled:</span>
|
||||
<span>{{ $projectsCompiled ?? '146' }}</span>
|
||||
</li>
|
||||
<li class="d-flex align-items-end">
|
||||
<i class="ti ti-users ti-lg"></i>
|
||||
<span class="fw-medium mx-2">Connections:</span>
|
||||
<span>{{ $connections ?? '897' }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
117
resources/views/components/user/details/permissions.blade.php
Normal file
117
resources/views/components/user/details/permissions.blade.php
Normal file
@ -0,0 +1,117 @@
|
||||
@props(['user' => null])
|
||||
|
||||
@php
|
||||
use Illuminate\Support\Str;
|
||||
use Koneko\VuexyAdmin\Models\PermissionGroup;
|
||||
|
||||
$permissions = $user?->getAllPermissionMetas() ?? collect();
|
||||
$groupedPermissions = $permissions->groupBy(fn($perm) => optional($perm->group)->module ?? 'Sin módulo');
|
||||
|
||||
$moduleDescriptions = PermissionGroup::query()
|
||||
->where('type', 'module')
|
||||
->get()
|
||||
->keyBy('module')
|
||||
->map(fn($group) => [
|
||||
'name' => $group->name[app()->getLocale()] ?? $group->module,
|
||||
'description' => $group->ui_metadata['description'][app()->getLocale()] ?? '',
|
||||
'icon' => $group->ui_metadata['icon'] ?? 'ti ti-box',
|
||||
]);
|
||||
@endphp
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<div class="row">
|
||||
@forelse($groupedPermissions as $module => $groupItems)
|
||||
@php
|
||||
$subGroups = $groupItems->groupBy(fn($perm) => optional($perm->group)->sub_grupo ?? 'General');
|
||||
$moduleInfo = $moduleDescriptions[$module] ?? null;
|
||||
@endphp
|
||||
|
||||
<div class="col-md-12 col-xl-6 mb-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-start pb-1">
|
||||
{{-- Sección izquierda: ícono + título --}}
|
||||
<div class="d-flex flex-column">
|
||||
<div class="d-flex align-items-center gap-2 mb-1">
|
||||
<i class="{{ $moduleInfo['icon'] ?? 'ti ti-box' }} text-lg text-muted"></i>
|
||||
<div>
|
||||
<div class="fw-semibold">{{ $moduleInfo['name'] ?? $module }}</div>
|
||||
<small class="text-muted small">{{ $module }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Contador de permisos --}}
|
||||
<div class="text-end">
|
||||
<span class="text-primary fw-semibold small" aria-label="Total de permisos">
|
||||
{{ $groupItems->count() }} permiso{{ $groupItems->count() === 1 ? '' : 's' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body py-0">
|
||||
{{-- Descripción general del módulo --}}
|
||||
@if(!empty($moduleInfo['description']))
|
||||
<p class="mb-0">{{ $moduleInfo['description'] }}</p>
|
||||
@endif
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
@foreach($subGroups as $sub => $items)
|
||||
<hr>
|
||||
<div class="mt-3">
|
||||
<h6 class="text-primary mb-1">
|
||||
{{ Str::headline($sub) }}
|
||||
<span class="text-muted fw-normal">({{ $items->count() }})</span>
|
||||
</h6>
|
||||
|
||||
@php
|
||||
$groupInfo = $items->first()?->group;
|
||||
$subGroupDescription = $groupInfo->ui_metadata['description'][app()->getLocale()] ?? null;
|
||||
|
||||
$actions = $items
|
||||
->filter(fn($perm) => method_exists($perm, 'getActionLabel'))
|
||||
->map(fn($perm) => $perm->getActionLabel())
|
||||
->unique()
|
||||
->implode(', ');
|
||||
@endphp
|
||||
|
||||
@if($subGroupDescription)
|
||||
<p class="small mb-3">{{ $subGroupDescription }}</p>
|
||||
@endif
|
||||
|
||||
@if($actions)
|
||||
<p class="text-muted small mb-2">Acciones: {{ $actions }}</p>
|
||||
@endif
|
||||
|
||||
<ul class="list-unstyled small">
|
||||
@foreach($items as $perm)
|
||||
<li class="mb-2">
|
||||
<div class="d-flex justify-content-between align-items-center px-2 py-1">
|
||||
<div class="d-flex align-items-center gap-1 flex-grow-1 text-wrap">
|
||||
<i class="ti ti-key text-muted"></i>
|
||||
<span class="text-break">
|
||||
{{ $perm->getDisplayName() }}
|
||||
</span>
|
||||
</div>
|
||||
<i class="ti ti-code text-muted cursor-pointer"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
data-bs-original-title="{{ $perm->name }}">
|
||||
</i>
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="col-12">
|
||||
<div class="alert alert-warning">Este usuario no tiene permisos asignados.</div>
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
26
resources/views/components/user/details/tabs.blade.php
Normal file
26
resources/views/components/user/details/tabs.blade.php
Normal file
@ -0,0 +1,26 @@
|
||||
<!-- resources/views/components/user/details/tabs.blade.php -->
|
||||
@props([
|
||||
'tabs' => [
|
||||
['label' => 'Profile', 'icon' => 'ti ti-user-check', 'active' => true, 'url' => '#'],
|
||||
['label' => 'Teams', 'icon' => 'ti ti-users', 'active' => false, 'url' => '#'],
|
||||
['label' => 'Projects', 'icon' => 'ti ti-layout-grid', 'active' => false, 'url' => '#'],
|
||||
['label' => 'Connections', 'icon' => 'ti ti-link', 'active' => false, 'url' => '#'],
|
||||
],
|
||||
])
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="nav-align-top">
|
||||
<ul class="nav nav-pills flex-column flex-sm-row mb-6 gap-2 gap-lg-0">
|
||||
@foreach ($tabs as $tab)
|
||||
<li class="nav-item">
|
||||
<a href="{{ $tab['url']?? 'javascript:;' }}"
|
||||
class="nav-link {{ $tab['active']?? false ? 'active' : '' }} waves-effect waves-light">
|
||||
<i class="ti-sm {{ $tab['icon']?? 'ti ti-user-check' }} me-1_5"></i> {{ $tab['label']?? 'No label' }}
|
||||
</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
56
resources/views/components/user/details/teams.blade.php
Normal file
56
resources/views/components/user/details/teams.blade.php
Normal file
@ -0,0 +1,56 @@
|
||||
<!-- resources/views/components/user/details/teams.blade.php -->
|
||||
@props([
|
||||
'teams' => [
|
||||
['name' => 'React Developers', 'members' => 72, 'badge' => 'Developer', 'badgeColor' => 'danger', 'avatar' => 'img/icons/brands/react-label.png'],
|
||||
['name' => 'Support Team', 'members' => 122, 'badge' => 'Support', 'badgeColor' => 'primary', 'avatar' => 'img/icons/brands/support-label.png'],
|
||||
['name' => 'UI Designers', 'members' => 7, 'badge' => 'Designer', 'badgeColor' => 'info', 'avatar' => 'img/icons/brands/figma-label.png'],
|
||||
['name' => 'Vue.js Developers', 'members' => 289, 'badge' => 'Developer', 'badgeColor' => 'danger', 'avatar' => 'img/icons/brands/vue-label.png'],
|
||||
['name' => 'Digital Marketing', 'members' => 24, 'badge' => 'Marketing', 'badgeColor' => 'secondary', 'avatar' => 'img/icons/brands/twitter-label.png'],
|
||||
],
|
||||
])
|
||||
|
||||
<div class="card card-action mb-6">
|
||||
<div class="card-header align-items-center">
|
||||
<h5 class="card-action-title mb-0">Teams</h5>
|
||||
<div class="card-action-element">
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-icon btn-text-secondary dropdown-toggle hide-arrow p-0 waves-effect waves-light" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="ti ti-dots-vertical text-muted"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item waves-effect" href="javascript:void(0);">Share teams</a></li>
|
||||
<li><a class="dropdown-item waves-effect" href="javascript:void(0);">Suggest edits</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item waves-effect" href="javascript:void(0);">Report bug</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled mb-0">
|
||||
@foreach ($teams as $team)
|
||||
<li class="mb-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar me-2">
|
||||
<img src="{{ asset($team['avatar']) }}" alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div class="me-2">
|
||||
<h6 class="mb-0">{{ $team['name'] }}</h6>
|
||||
<small>{{ $team['members'] }} Members</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ms-auto">
|
||||
<a href="javascript:;">
|
||||
<span class="badge bg-label-{{ $team['badgeColor'] }}">{{ $team['badge'] }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
<li class="text-center">
|
||||
<a href="javascript:;">View all teams</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
105
resources/views/components/user/details/timeline.blade.php
Normal file
105
resources/views/components/user/details/timeline.blade.php
Normal file
@ -0,0 +1,105 @@
|
||||
@props([
|
||||
'items' => [
|
||||
[
|
||||
'icon' => 'primary',
|
||||
'title' => '12 Invoices have been paid',
|
||||
'time' => '12 min ago',
|
||||
'description' => 'Invoices have been paid to the company',
|
||||
'attachment' => [
|
||||
'icon' => 'pdf',
|
||||
'label' => 'invoices.pdf'
|
||||
]
|
||||
],
|
||||
[
|
||||
'icon' => 'success',
|
||||
'title' => 'Client Meeting',
|
||||
'time' => '45 min ago',
|
||||
'description' => 'Project meeting with john @10:15am',
|
||||
'user' => [
|
||||
'avatar' => 'http://vuexy-vite.test/assets/img/avatars/1.png',
|
||||
'name' => 'Lester McCarthy',
|
||||
'role' => 'CEO of Pixinvent'
|
||||
]
|
||||
],
|
||||
[
|
||||
'icon' => 'info',
|
||||
'title' => 'Create a new project for client',
|
||||
'time' => '2 Days Ago',
|
||||
'description' => '6 team members in a project',
|
||||
'users' => [
|
||||
['avatar' => 'http://vuexy-vite.test/assets/img/avatars/1.png', 'name' => 'Vinnie Mostowy'],
|
||||
['avatar' => 'http://vuexy-vite.test/assets/img/avatars/4.png', 'name' => 'Allen Rieske'],
|
||||
['avatar' => 'http://vuexy-vite.test/assets/img/avatars/2.png', 'name' => 'Julee Rossignol'],
|
||||
['avatar' => null, 'initials' => '+3']
|
||||
]
|
||||
]
|
||||
]
|
||||
])
|
||||
|
||||
<div class="card card-action mb-6">
|
||||
<div class="card-header align-items-center">
|
||||
<h5 class="card-action-title mb-0">
|
||||
<i class="ti ti-chart-bar ti-lg text-body me-4"></i>Activity Timeline
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<ul class="timeline mb-0">
|
||||
@foreach($items as $item)
|
||||
<li class="timeline-item timeline-item-transparent">
|
||||
<span class="timeline-point timeline-point-{{ $item['icon'] }}"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-3">
|
||||
<h6 class="mb-0">{{ $item['title'] }}</h6>
|
||||
<small class="text-muted">{{ $item['time'] }}</small>
|
||||
</div>
|
||||
<p class="mb-2">{{ $item['description'] }}</p>
|
||||
|
||||
@isset($item['attachment'])
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="badge bg-lighter rounded d-flex align-items-center">
|
||||
<img src="http://vuexy-vite.test/assets/img/icons/misc/{{ $item['attachment']['icon'] }}.png" alt="icon" width="15" class="me-2">
|
||||
<span class="h6 mb-0 text-body">{{ $item['attachment']['label'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
|
||||
@isset($item['user'])
|
||||
<div class="d-flex justify-content-between flex-wrap gap-2 mb-2">
|
||||
<div class="d-flex flex-wrap align-items-center mb-50">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<img src="{{ $item['user']['avatar'] }}" alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-0 small fw-medium">{{ $item['user']['name'] }}</p>
|
||||
<small>{{ $item['user']['role'] }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
|
||||
@isset($item['users'])
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center flex-wrap border-top-0 p-0">
|
||||
<div class="d-flex flex-wrap align-items-center">
|
||||
<ul class="list-unstyled users-list d-flex align-items-center avatar-group m-0 me-2">
|
||||
@foreach($item['users'] as $u)
|
||||
<li class="avatar pull-up" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ $u['name'] ?? '' }}">
|
||||
@if(isset($u['avatar']))
|
||||
<img class="rounded-circle" src="{{ $u['avatar'] }}" alt="Avatar">
|
||||
@else
|
||||
<span class="avatar-initial rounded-circle pull-up text-heading">{{ $u['initials'] }}</span>
|
||||
@endif
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@endisset
|
||||
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
@ -25,7 +25,7 @@
|
||||
{{ __('errors.bad_request') }}
|
||||
@endif
|
||||
</p>
|
||||
<a href="{{ route('admin.core.home.index') }}" class="btn btn-primary mb-10">Regresar al inicio</a>
|
||||
<a href="{{ route('admin.core.pages.home.index') }}" class="btn btn-primary mb-10">Regresar al inicio</a>
|
||||
<div class="mt-4">
|
||||
<img src="{{ asset('vendor/vuexy-admin/img/illustrations/page-misc-error.png') }}" alt="page-misc-error" width="225" class="img-fluid">
|
||||
</div>
|
||||
|
@ -25,7 +25,7 @@
|
||||
{{ __('errors.unauthorized') }}
|
||||
@endif
|
||||
</p>
|
||||
<a href="{{ route('admin.core.home.index') }}" class="btn btn-primary mb-10">Regresar al inicio</a>
|
||||
<a href="{{ route('admin.core.pages.home.index') }}" class="btn btn-primary mb-10">Regresar al inicio</a>
|
||||
<div class="mt-4">
|
||||
<img src="{{ asset('vendor/vuexy-admin/img/illustrations/page-misc-you-are-not-authorized.png') }}" alt="page-misc-not-authorized" width="170" class="img-fluid">
|
||||
</div>
|
||||
|
@ -25,7 +25,7 @@
|
||||
{{ __('errors.forbidden') }}
|
||||
@endif
|
||||
</p>
|
||||
<a href="{{ route('admin.core.home.index') }}" class="btn btn-primary mb-10">Regresar al inicio</a>
|
||||
<a href="{{ route('admin.core.pages.home.index') }}" class="btn btn-primary mb-10">Regresar al inicio</a>
|
||||
<div class="mt-4">
|
||||
<img src="{{ asset('vendor/vuexy-admin/img/illustrations/page-misc-you-are-not-authorized.png') }}" alt="page-misc-not-authorized" width="170" class="img-fluid">
|
||||
</div>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<p class="mb-6 mx-2">
|
||||
{{ __('errors.page_not_found') }}
|
||||
</p>
|
||||
<a href="{{ route('admin.core.home.index') }}" class="btn btn-primary mb-10">Regresar al inicio</a>
|
||||
<a href="{{ route('admin.core.pages.home.index') }}" class="btn btn-primary mb-10">Regresar al inicio</a>
|
||||
<div class="mt-4">
|
||||
<img src="{{ asset('vendor/vuexy-admin/img/illustrations/page-misc-error.png') }}" alt="page-misc-error" width="225" class="img-fluid">
|
||||
</div>
|
||||
|
@ -0,0 +1,7 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Configuración de módulos')
|
||||
|
||||
@section('content')
|
||||
@livewire('vuexy-admin::module-management-index')
|
||||
@endsection
|
7
resources/views/koneko-vuexy/plugins/index.blade.php
Normal file
7
resources/views/koneko-vuexy/plugins/index.blade.php
Normal file
@ -0,0 +1,7 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Plugins Koneko Vuexy Admin')
|
||||
|
||||
@section('content')
|
||||
@livewire('vuexy-admin::plugins-index')
|
||||
@endsection
|
@ -11,6 +11,10 @@ $customizerHidden = ($customizerHidden ?? '');
|
||||
@extends('vuexy-admin::layouts.vuexy.commonMaster' )
|
||||
|
||||
@section('layoutContent')
|
||||
<!-- Notifications -->
|
||||
<div class="notification-container"></div>
|
||||
<!-- / Notifications -->
|
||||
|
||||
<!-- Content -->
|
||||
@yield('content')
|
||||
<!--/ Content -->
|
||||
|
@ -1,58 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
@php
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
$menuFixed = ($configData['layout'] === 'vertical') ? ($menuFixed ?? '') : (($configData['layout'] === 'front') ? '' : $configData['headerType']);
|
||||
$navbarType = ($configData['layout'] === 'vertical') ? ($configData['navbarType'] ?? '') : (($configData['layout'] === 'front') ? 'layout-navbar-fixed': '');
|
||||
$isFront = ($isFront ?? '') == true ? 'Front' : '';
|
||||
$contentLayout = (isset($container) ? (($container === 'container-xxl') ? "layout-compact" : "layout-wide") : "");
|
||||
$menuFixed = ($configData['layout'] === 'vertical') ? ($menuFixed ?? '') : (($configData['layout'] === 'front') ? '' : $configData['headerType']);
|
||||
$navbarType = ($configData['layout'] === 'vertical') ? ($configData['navbarType'] ?? '') : (($configData['layout'] === 'front') ? 'layout-navbar-fixed': '');
|
||||
$isFront = ($isFront ?? '') == true ? 'Front' : '';
|
||||
$contentLayout = (isset($container) ? (($container === 'container-xxl') ? "layout-compact" : "layout-wide") : "");
|
||||
@endphp
|
||||
|
||||
<html lang="{{ session()->get('locale') ?? app()->getLocale() }}"
|
||||
class="{{ $configData['style'] }}-style {{($contentLayout ?? '')}} {{ ($navbarType ?? '') }} {{ ($menuFixed ?? '') }} {{ $menuCollapsed ?? '' }} {{ $menuFlipped ?? '' }} {{ $menuOffcanvas ?? '' }} {{ $footerFixed ?? '' }} {{ $customizerHidden ?? '' }}"
|
||||
dir="{{ $configData['textDirection'] }}"
|
||||
data-theme="{{ $configData['theme'] }}"
|
||||
data-assets-path="{{ asset('/assets') . '/' }}"
|
||||
data-base-url="{{ url('/') . '/' }}"
|
||||
data-quicklinks-update-url="{{ route('admin.core.quicklinks-navbar.update') }}"
|
||||
data-route="{{ Route::currentRouteName() }}"
|
||||
data-framework="laravel"
|
||||
data-template="{{ $configData['layout'] . '-menu-' . $configData['themeOpt'] . '-' . $configData['styleOpt'] }}"
|
||||
data-style="{{$configData['styleOptVal']}}">
|
||||
|
||||
class="{{ $configData['style'] }}-style {{($contentLayout ?? '')}} {{ ($navbarType ?? '') }} {{ ($menuFixed ?? '') }} {{ $menuCollapsed ?? '' }} {{ $menuFlipped ?? '' }} {{ $menuOffcanvas ?? '' }} {{ $footerFixed ?? '' }} {{ $customizerHidden ?? '' }}"
|
||||
dir="{{ $configData['textDirection'] }}"
|
||||
data-theme="{{ $configData['theme'] }}"
|
||||
data-assets-path="{{ asset('/assets') . '/' }}"
|
||||
data-base-url="{{ url('/') . '/' }}"
|
||||
data-route="{{ Route::currentRouteName() }}"
|
||||
data-framework="laravel"
|
||||
data-template="{{ $configData['layout'] . '-menu-' . $configData['themeOpt'] . '-' . $configData['styleOpt'] }}"
|
||||
data-style="{{$configData['styleOptVal']}}">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
|
||||
|
||||
<title>@hasSection('title') @yield('title') | @endif {{ $_admin['title'] }}</title>
|
||||
<meta name="description" content="{{ $_admin['description'] }}" />
|
||||
<title>@hasSection('title') @yield('title') | @endif {{ $_admin['title'] }}</title>
|
||||
<meta name="description" content="{{ $_admin['description'] }}" />
|
||||
|
||||
<!-- laravel CRUD token -->
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<!-- laravel CRUD token -->
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<!-- Favicons-->
|
||||
<link rel="icon" href="{{ asset('storage/' . $_admin['favicon']['16x16']) }}" type="image/x-icon">
|
||||
<link rel="icon" sizes="192x192" href="{{ asset('storage/' . $_admin['favicon']['192x192']) }}">
|
||||
<link rel="apple-touch-icon" type="image/x-icon" sizes="76x76" href="{{ asset('storage/' . $_admin['favicon']['76x76']) }}">
|
||||
<link rel="apple-touch-icon" type="image/x-icon" sizes="120x120" href="{{ asset('storage/' . $_admin['favicon']['120x120']) }}">
|
||||
<link rel="apple-touch-icon" type="image/x-icon" sizes="152x152" href="{{ asset('storage/' . $_admin['favicon']['152x152']) }}">
|
||||
<link rel="apple-touch-icon" type="image/x-icon" sizes="180x180" href="{{ asset('storage/' . $_admin['favicon']['180x180']) }}">
|
||||
<!-- Favicons-->
|
||||
<link rel="icon" href="{{ asset('storage/' . $_admin['favicon']['16x16']) }}" type="image/x-icon">
|
||||
<link rel="icon" sizes="192x192" href="{{ asset('storage/' . $_admin['favicon']['192x192']) }}">
|
||||
<link rel="apple-touch-icon" type="image/x-icon" sizes="76x76" href="{{ asset('storage/' . $_admin['favicon']['76x76']) }}">
|
||||
<link rel="apple-touch-icon" type="image/x-icon" sizes="120x120" href="{{ asset('storage/' . $_admin['favicon']['120x120']) }}">
|
||||
<link rel="apple-touch-icon" type="image/x-icon" sizes="152x152" href="{{ asset('storage/' . $_admin['favicon']['152x152']) }}">
|
||||
<link rel="apple-touch-icon" type="image/x-icon" sizes="180x180" href="{{ asset('storage/' . $_admin['favicon']['180x180']) }}">
|
||||
|
||||
<!-- Include Styles -->
|
||||
<!-- $isFront is used to append the front layout styles only on the front layout otherwise the variable will be blank -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.styles' . $isFront)
|
||||
<!-- Include Styles -->
|
||||
<!-- $isFront is used to append the front layout styles only on the front layout otherwise the variable will be blank -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.styles' . $isFront)
|
||||
|
||||
<!-- Include Scripts for customizer, helper, analytics, config -->
|
||||
<!-- $isFront is used to append the front layout scriptsIncludes only on the front layout otherwise the variable will be blank -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.scriptsIncludes' . $isFront)
|
||||
<!-- Include Scripts for customizer, helper, analytics, config -->
|
||||
<!-- $isFront is used to append the front layout scriptsIncludes only on the front layout otherwise the variable will be blank -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.scriptsIncludes' . $isFront)
|
||||
|
||||
<!-- Notifications -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.notifySession')
|
||||
</head>
|
||||
<body>
|
||||
<!-- Layout Content -->
|
||||
@yield('layoutContent')
|
||||
<!--/ Layout Content -->
|
||||
<!-- Layout Content -->
|
||||
@yield('layoutContent')
|
||||
<!--/ Layout Content -->
|
||||
|
||||
<!-- Include Scripts -->
|
||||
<!-- $isFront is used to append the front layout scripts only on the front layout otherwise the variable will be blank -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.scripts' . $isFront)
|
||||
<!-- Include Scripts -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.scripts' . $isFront)
|
||||
</body>
|
||||
</html>
|
||||
|
@ -20,7 +20,7 @@ $customizerHidden = ($customizerHidden ?? '');
|
||||
$navbarDetached = 'navbar-detached';
|
||||
$menuFixed = (isset($configData['menuFixed']) ? $configData['menuFixed'] : '');
|
||||
if(isset($navbarType)) {
|
||||
$configData['navbarType'] = $navbarType;
|
||||
$configData['navbarType'] = $navbarType;
|
||||
}
|
||||
$navbarType = (isset($configData['navbarType']) ? $configData['navbarType'] : '');
|
||||
$footerFixed = (isset($configData['footerFixed']) ? $configData['footerFixed'] : '');
|
||||
@ -32,58 +32,60 @@ $container = (isset($configData['contentLayout']) && $configData['contentLayout'
|
||||
|
||||
@section('layoutContent')
|
||||
<div class="layout-wrapper layout-content-navbar {{ $isMenu ? '' : 'layout-without-menu' }}">
|
||||
<div class="layout-container">
|
||||
<div class="layout-container">
|
||||
|
||||
@if ($isMenu)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.menu.verticalMenu')
|
||||
@endif
|
||||
@if ($isMenu)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.menu.verticalMenu')
|
||||
@endif
|
||||
|
||||
<!-- Layout page -->
|
||||
<div class="layout-page">
|
||||
<!-- Layout page -->
|
||||
<div class="layout-page">
|
||||
|
||||
<!-- BEGIN: Navbar-->
|
||||
@if ($isNavbar)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.navbar.navbar')
|
||||
@endif
|
||||
<!-- END: Navbar-->
|
||||
|
||||
<!-- Content wrapper -->
|
||||
<div class="content-wrapper">
|
||||
|
||||
<!-- Content -->
|
||||
@if ($isFlex)
|
||||
<div class="{{$container}} d-flex align-items-stretch flex-grow-1 p-0">
|
||||
@else
|
||||
<div class="{{$container}} flex-grow-1 container-p-y">
|
||||
<!-- BEGIN: Navbar-->
|
||||
@if ($isNavbar)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.navbar.navbar')
|
||||
@endif
|
||||
<!-- END: Navbar-->
|
||||
|
||||
<!-- Breadcrumbs -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.content.breadcrumbs')
|
||||
<!-- / Breadcrumbs -->
|
||||
<!-- Content wrapper -->
|
||||
<div class="content-wrapper">
|
||||
|
||||
@yield('content')
|
||||
<!-- Content -->
|
||||
@if ($isFlex)
|
||||
<div class="{{$container}} d-flex align-items-stretch flex-grow-1 p-0">
|
||||
@else
|
||||
<div class="{{$container}} flex-grow-1 container-p-y">
|
||||
@endif
|
||||
<!-- Breadcrumbs -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.content.breadcrumbs')
|
||||
<!-- / Breadcrumbs -->
|
||||
|
||||
</div>
|
||||
<!-- / Content -->
|
||||
<!-- Notifications -->
|
||||
<div class="notification-container"></div>
|
||||
<!-- / Notifications -->
|
||||
|
||||
<!-- Footer -->
|
||||
@if ($isFooter)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.footer.footer')
|
||||
@endif
|
||||
<!-- / Footer -->
|
||||
<div class="content-backdrop fade"></div>
|
||||
@yield('content')
|
||||
</div>
|
||||
<!-- / Content -->
|
||||
|
||||
<!-- Footer -->
|
||||
@if ($isFooter)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.footer.footer')
|
||||
@endif
|
||||
<!-- / Footer -->
|
||||
<div class="content-backdrop fade"></div>
|
||||
</div>
|
||||
<!--/ Content wrapper -->
|
||||
</div>
|
||||
<!-- / Layout page -->
|
||||
</div>
|
||||
<!--/ Content wrapper -->
|
||||
</div>
|
||||
<!-- / Layout page -->
|
||||
</div>
|
||||
|
||||
@if ($isMenu)
|
||||
<!-- Overlay -->
|
||||
<div class="layout-overlay layout-menu-toggle"></div>
|
||||
@endif
|
||||
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
|
||||
<div class="drag-target"></div>
|
||||
</div>
|
||||
<!-- / Layout wrapper -->
|
||||
@endsection
|
||||
@if ($isMenu)
|
||||
<!-- Overlay -->
|
||||
<div class="layout-overlay layout-menu-toggle"></div>
|
||||
@endif
|
||||
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
|
||||
<div class="drag-target"></div>
|
||||
</div>
|
||||
<!-- / Layout wrapper -->
|
||||
@endsection
|
||||
|
@ -1,87 +1,91 @@
|
||||
@isset($pageConfigs)
|
||||
{!! Helper::updatePageConfig($pageConfigs) !!}
|
||||
{!! Helper::updatePageConfig($pageConfigs) !!}
|
||||
@endisset
|
||||
@php
|
||||
$configData = Helper::appClasses();
|
||||
$configData = Helper::appClasses();
|
||||
@endphp
|
||||
|
||||
@extends('vuexy-admin::layouts.vuexy.commonMaster' )
|
||||
|
||||
@php
|
||||
$menuHorizontal = true;
|
||||
$navbarFull = true;
|
||||
$menuHorizontal = true;
|
||||
$navbarFull = true;
|
||||
|
||||
/* Display elements */
|
||||
$isNavbar = ($isNavbar ?? true);
|
||||
$isMenu = ($isMenu ?? true);
|
||||
$isFlex = ($isFlex ?? false);
|
||||
$isFooter = ($isFooter ?? true);
|
||||
$customizerHidden = ($customizerHidden ?? '');
|
||||
/* Display elements */
|
||||
$isNavbar = ($isNavbar ?? true);
|
||||
$isMenu = ($isMenu ?? true);
|
||||
$isFlex = ($isFlex ?? false);
|
||||
$isFooter = ($isFooter ?? true);
|
||||
$customizerHidden = ($customizerHidden ?? '');
|
||||
|
||||
/* HTML Classes */
|
||||
$menuFixed = (isset($configData['menuFixed']) ? $configData['menuFixed'] : '');
|
||||
$navbarType = (isset($configData['navbarType']) ? $configData['navbarType'] : '');
|
||||
$footerFixed = (isset($configData['footerFixed']) ? $configData['footerFixed'] : '');
|
||||
$menuCollapsed = (isset($configData['menuCollapsed']) ? $configData['menuCollapsed'] : '');
|
||||
/* HTML Classes */
|
||||
$menuFixed = (isset($configData['menuFixed']) ? $configData['menuFixed'] : '');
|
||||
$navbarType = (isset($configData['navbarType']) ? $configData['navbarType'] : '');
|
||||
$footerFixed = (isset($configData['footerFixed']) ? $configData['footerFixed'] : '');
|
||||
$menuCollapsed = (isset($configData['menuCollapsed']) ? $configData['menuCollapsed'] : '');
|
||||
|
||||
/* Content classes */
|
||||
$container = ($configData['contentLayout'] === 'compact') ? 'container-xxl' : 'container-fluid';
|
||||
$containerNav = ($configData['contentLayout'] === 'compact') ? 'container-xxl' : 'container-fluid';
|
||||
/* Content classes */
|
||||
$container = ($configData['contentLayout'] === 'compact') ? 'container-xxl' : 'container-fluid';
|
||||
$containerNav = ($configData['contentLayout'] === 'compact') ? 'container-xxl' : 'container-fluid';
|
||||
@endphp
|
||||
|
||||
@section('layoutContent')
|
||||
<div class="layout-wrapper layout-navbar-full layout-horizontal layout-without-menu">
|
||||
<div class="layout-container">
|
||||
<div class="layout-container">
|
||||
|
||||
<!-- BEGIN: Navbar-->
|
||||
@if ($isNavbar)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.navbar.navbar')
|
||||
@endif
|
||||
<!-- END: Navbar-->
|
||||
<!-- BEGIN: Navbar-->
|
||||
@if ($isNavbar)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.navbar.navbar')
|
||||
@endif
|
||||
<!-- END: Navbar-->
|
||||
|
||||
<!-- Layout page -->
|
||||
<div class="layout-page">
|
||||
<!-- Layout page -->
|
||||
<div class="layout-page">
|
||||
|
||||
<!-- Content wrapper -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content wrapper -->
|
||||
<div class="content-wrapper">
|
||||
|
||||
@if ($isMenu)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.menu.horizontalMenu')
|
||||
@endif
|
||||
|
||||
<!-- Content -->
|
||||
@if ($isFlex)
|
||||
<div class="{{$container}} d-flex align-items-stretch flex-grow-1 p-0">
|
||||
@else
|
||||
<div class="{{$container}} flex-grow-1 container-p-y">
|
||||
@endif
|
||||
<!-- Breadcrumbs -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.content.breadcrumbs')
|
||||
<!-- / Breadcrumbs -->
|
||||
|
||||
<!-- Notifications -->
|
||||
<div class="notification-container"></div>
|
||||
<!-- / Notifications -->
|
||||
|
||||
@yield('content')
|
||||
</div>
|
||||
<!-- / Content -->
|
||||
|
||||
<!-- Footer -->
|
||||
@if ($isFooter)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.footer.footer')
|
||||
@endif
|
||||
<!-- / Footer -->
|
||||
<div class="content-backdrop fade"></div>
|
||||
</div>
|
||||
<!--/ Content wrapper -->
|
||||
</div>
|
||||
<!-- / Layout page -->
|
||||
</div>
|
||||
<!-- / Layout Container -->
|
||||
|
||||
@if ($isMenu)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.menu.horizontalMenu')
|
||||
<!-- Overlay -->
|
||||
<div class="layout-overlay layout-menu-toggle"></div>
|
||||
@endif
|
||||
|
||||
<!-- Content -->
|
||||
@if ($isFlex)
|
||||
<div class="{{$container}} d-flex align-items-stretch flex-grow-1 p-0">
|
||||
@else
|
||||
<div class="{{$container}} flex-grow-1 container-p-y">
|
||||
@endif
|
||||
<!-- Breadcrumbs -->
|
||||
@include('vuexy-admin::layouts.vuexy.sections.content.breadcrumbs')
|
||||
<!-- / Breadcrumbs -->
|
||||
|
||||
@yield('content')
|
||||
</div>
|
||||
<!-- / Content -->
|
||||
|
||||
<!-- Footer -->
|
||||
@if ($isFooter)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.footer.footer')
|
||||
@endif
|
||||
<!-- / Footer -->
|
||||
<div class="content-backdrop fade"></div>
|
||||
</div>
|
||||
<!--/ Content wrapper -->
|
||||
</div>
|
||||
<!-- / Layout page -->
|
||||
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
|
||||
<div class="drag-target"></div>
|
||||
</div>
|
||||
<!-- / Layout Container -->
|
||||
|
||||
@if ($isMenu)
|
||||
<!-- Overlay -->
|
||||
<div class="layout-overlay layout-menu-toggle"></div>
|
||||
@endif
|
||||
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
|
||||
<div class="drag-target"></div>
|
||||
</div>
|
||||
<!-- / Layout wrapper -->
|
||||
@endsection
|
||||
<!-- / Layout wrapper -->
|
||||
@endsection
|
||||
|
@ -3,16 +3,12 @@
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
@foreach ($vuexyBreadcrumbs as $breadcrumb)
|
||||
<li class="breadcrumb-item {{ isset($breadcrumb['active']) && $breadcrumb['active']? 'active': '' }}">
|
||||
@php
|
||||
if(isset($breadcrumb['route']) && isset($breadcrumb['link']) == false)
|
||||
$breadcrumb['link'] = route($breadcrumb['route']);
|
||||
@endphp
|
||||
@isset($breadcrumb['link'])
|
||||
<li class="breadcrumb-item {{ $breadcrumb['active'] ? 'active' : '' }}">
|
||||
@if(!$breadcrumb['active'] && isset($breadcrumb['link']))
|
||||
<a href="{{ $breadcrumb['link'] }}">{{ $breadcrumb['name'] }}</a>
|
||||
@else
|
||||
{{ $breadcrumb['name'] }}
|
||||
@endisset
|
||||
@endif
|
||||
</li>
|
||||
@endforeach
|
||||
</ol>
|
||||
|
36
resources/views/layouts/vuexy/sections/menu/_item.blade.php
Normal file
36
resources/views/layouts/vuexy/sections/menu/_item.blade.php
Normal file
@ -0,0 +1,36 @@
|
||||
@php
|
||||
$meta = $item['_meta'] ?? [];
|
||||
$slug = $item['_slug'] ?? null;
|
||||
$icon = $meta['icon'] ?? $item['icon'] ?? null;
|
||||
$count = $meta['count'] ?? 0;
|
||||
$url = $item['url'] ?? 'javascript:void(0);';
|
||||
$label = $meta['label'] ?? $label;
|
||||
$badge = $meta['badge'] ?? null;
|
||||
$target = isset($item['target']) ? 'target="'.$item['target'].'"' : '';
|
||||
$active = $meta['active'] ?? false;
|
||||
$hasSubmenu = isset($item['submenu']) && is_array($item['submenu']);
|
||||
$autoId = $meta['auto_id'] ?? null;
|
||||
|
||||
$classes = 'menu-item' . ($active ? ' active' : '');
|
||||
$linkClass = 'menu-link' . ($hasSubmenu ? ' menu-toggle' : '');
|
||||
@endphp
|
||||
|
||||
<li class="{{ $classes }}">
|
||||
<a href="{{ $url }}" class="{{ $linkClass }}" {!! $target !!}>
|
||||
@isset($icon)
|
||||
<i class="menu-icon tf-icons {{ $icon }}"></i>
|
||||
@endisset
|
||||
<div>{{ $label }}</div>
|
||||
@isset($badge)
|
||||
<div class="badge bg-{{ $badge['level'] ?? 'secondary' }} rounded-pill ms-auto">{{ $badge['label'] ?? '' }}</div>
|
||||
@endisset
|
||||
</a>
|
||||
|
||||
@if ($hasSubmenu)
|
||||
<ul class="menu-sub">
|
||||
@foreach ($item['submenu'] as $subLabel => $subItem)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.menu._item', ['label' => $subLabel, 'item' => $subItem])
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
</li>
|
@ -2,27 +2,12 @@
|
||||
$configData = Helper::appClasses();
|
||||
@endphp
|
||||
|
||||
<!-- Horizontal Menu -->
|
||||
<aside id="layout-menu" class="layout-menu-horizontal menu-horizontal menu bg-menu-theme flex-grow-0">
|
||||
<div class="{{$containerNav}} d-flex h-100">
|
||||
<div class="{{ $containerNav }} d-flex h-100">
|
||||
<ul class="menu-inner pb-2 pb-xl-0">
|
||||
@foreach ($vuexyMenu as $menuName => $menu)
|
||||
<li class="menu-item {{ isset($menu['active']) && $menu['active'] ? 'active' : '' }}">
|
||||
<a href="{{ $menu['url'] ?? 'javascript:void(0);' }}" class="menu-link {{ isset($menu['submenu']) ? 'menu-toggle' : '' }}" @if (isset($menu['target']) and !empty($menu['target'])) target="{{ $menu['target'] }}" @endif>
|
||||
@isset($menu['icon'])
|
||||
<i class="{{ $menu['icon'] }}"></i>
|
||||
@endisset
|
||||
<div>{{ $menuName }}</div>
|
||||
@isset($menu['badge'])
|
||||
<div class="badge bg-{{ $menu['badge'][0] }} rounded-pill ms-auto">{{ $menu['badge'][1] }}</div>
|
||||
@endisset
|
||||
</a>
|
||||
@isset($menu['submenu'])
|
||||
@include('vuexy-admin::layouts.vuexy.sections.menu.submenu', ['menu' => $menu['submenu']])
|
||||
@endisset
|
||||
</li>
|
||||
@foreach ($vuexyMenu as $label => $menu)
|
||||
@include('vuexy-admin::layouts.vuexy.sections.menu._item', ['label' => $label, 'item' => $menu])
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
<!--/ Horizontal Menu -->
|
||||
|
@ -3,7 +3,7 @@
|
||||
<li class="menu-item {{ isset($submenu['active']) && $submenu['active'] ? 'active open' : '' }}">
|
||||
<a href="{{ $submenu['url'] ?? 'javascript:void(0);' }}" class="menu-link {{ isset($submenu['submenu']) ? 'menu-toggle' : '' }}" @if (isset($submenu['target']) and !empty($submenu['target'])) target="{{ $submenu['target'] }}" @endif>
|
||||
@isset($submenu['icon'])
|
||||
<i class="{{ $submenu['icon'] }}"></i>
|
||||
<i class="menu-icon tf-icons {{ $submenu['icon'] }}"></i>
|
||||
@endisset
|
||||
<div>{{ $submenuName }}</div>
|
||||
@isset($submenu['badge'])
|
||||
|
@ -7,7 +7,7 @@
|
||||
<!-- ! Hide app brand if navbar-full -->
|
||||
@if(!isset($navbarFull))
|
||||
<div class="app-brand demo">
|
||||
<a href="{{ route('admin.core.home.index') }}" class="app-brand-link">
|
||||
<a href="{{ route('admin.core.pages.home.index') }}" class="app-brand-link">
|
||||
<span class="app-brand-logo demo">
|
||||
<img src="{{ asset('storage/' . $_admin['image_logo']['small']) }}" alt="{{ $_admin['app_name'] }}" />
|
||||
</span>
|
||||
@ -33,7 +33,7 @@
|
||||
<li class="menu-item {{ isset($menu['active']) && $menu['active'] ? 'active open' : '' }}">
|
||||
<a href="{{ $menu['url'] ?? 'javascript:void(0);' }}" class="menu-link {{ isset($menu['submenu']) ? 'menu-link menu-toggle' : 'menu-link' }}" @if (isset($menu['target']) and !empty($menu['target'])) target="{{ $menu['target'] }}" @endif>
|
||||
@isset($menu['icon'])
|
||||
<i class="{{ $menu['icon'] }}"></i>
|
||||
<i class="menu-icon tf-icons {{ $menu['icon'] }}"></i>
|
||||
@endisset
|
||||
<div>{{ $menuName }}</div>
|
||||
@isset($menu['badge'])
|
||||
|
@ -17,7 +17,7 @@ $navbarDetached = ($navbarDetached ?? '');
|
||||
<!-- Brand demo (display only for navbar-full and hide on below xl) -->
|
||||
@if(isset($navbarFull))
|
||||
<div class="navbar-brand app-brand demo d-none d-xl-flex py-0 me-4">
|
||||
<a href="{{ route('admin.core.home.index') }}" class="app-brand-link">
|
||||
<a href="{{ route('admin.core.pages.home.index') }}" class="app-brand-link">
|
||||
<span class="app-brand-logo demo">
|
||||
<img src="{{ asset('storage/' . $_admin['image_logo']['small']) }}" alt="{{ $_admin['app_name'] }}" />
|
||||
</span>
|
||||
@ -43,31 +43,69 @@ $navbarDetached = ($navbarDetached ?? '');
|
||||
<div class="navbar-nav-right d-flex align-items-center" id="navbar-collapse">
|
||||
@if(!isset($menuHorizontal))
|
||||
<!-- Search -->
|
||||
@if ($vuexySearch)
|
||||
<div class="navbar-nav align-items-center">
|
||||
<div class="nav-item navbar-search-wrapper mb-0">
|
||||
<a class="nav-item nav-link search-toggler d-flex align-items-center px-0" href="javascript:void(0);">
|
||||
<i class="ti ti-search ti-md me-2 me-lg-4 ti-lg"></i>
|
||||
<span class="d-none d-md-inline-block text-muted fw-normal">Buscar (Ctrl+/)</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-nav align-items-center">
|
||||
<div class="nav-item navbar-search-wrapper mb-0">
|
||||
<a class="nav-item nav-link search-toggler d-flex align-items-center px-0" href="javascript:void(0);">
|
||||
<i class="ti ti-search ti-md me-2 me-lg-4 ti-lg"></i>
|
||||
<span class="d-none d-md-inline-block text-muted fw-normal">Buscar (Ctrl+/)</span>
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<!-- /Search -->
|
||||
@endif
|
||||
<ul class="navbar-nav flex-row align-items-center ms-auto">
|
||||
@if(isset($menuHorizontal))
|
||||
<!-- Search -->
|
||||
@if ($vuexySearch)
|
||||
<li class="nav-item navbar-search-wrapper">
|
||||
<a class="nav-link btn btn-text-secondary btn-icon rounded-pill search-toggler" href="javascript:void(0);">
|
||||
<i class="ti ti-search ti-md"></i>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li class="nav-item navbar-search-wrapper">
|
||||
<a class="nav-link btn btn-text-secondary btn-icon rounded-pill search-toggler" href="javascript:void(0);">
|
||||
<i class="ti ti-search ti-md"></i>
|
||||
</a>
|
||||
</li>
|
||||
<!-- /Search -->
|
||||
@endif
|
||||
|
||||
<!-- Language -->
|
||||
<li class="nav-item dropdown-language dropdown">
|
||||
<a class="nav-link btn btn-text-secondary btn-icon rounded-pill dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown">
|
||||
<i class='ti ti-language rounded-circle ti-md'></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<a class="dropdown-item pr-2 {{ app()->getLocale() === 'es' ? 'active' : '' }}" href="{{url('lang/es')}}" data-language="es" data-text-direction="ltr">
|
||||
<img src="{{ asset('vendor/vuexy-admin/flag-icons/flags/1x1/mx.svg') }}" style="height:16px" class="inline" alt="">
|
||||
<span class="ml-1">Español México</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<li>
|
||||
<a class="dropdown-item {{ app()->getLocale() === 'co' ? 'active' : '' }}" href="{{url('lang/co')}}" data-language="co" data-text-direction="ltr">
|
||||
<img src="{{ asset('vendor/vuexy-admin/flag-icons/flags/1x1/co.svg') }}" style="height:16px" class="inline" alt="">
|
||||
<span class="ml-1">Español Colombia</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item {{ app()->getLocale() === 'en' ? 'active' : '' }}" href="{{url('lang/en')}}" data-language="en" data-text-direction="ltr">
|
||||
<img src="{{ asset('vendor/vuexy-admin/flag-icons/flags/1x1/us.svg') }}" style="height:16px" class="inline" alt="">
|
||||
<span class="ml-1">English</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item {{ app()->getLocale() === 'fr' ? 'active' : '' }}" href="{{url('lang/fr')}}" data-language="fr" data-text-direction="ltr">
|
||||
<img src="{{ asset('vendor/vuexy-admin/flag-icons/flags/1x1/fr.svg') }}" style="height:16px" class="inline" alt="">
|
||||
<span class="ml-1">French</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item {{ app()->getLocale() === 'de' ? 'active' : '' }}" href="{{url('lang/de')}}" data-language="de" data-text-direction="ltr">
|
||||
<img src="{{ asset('vendor/vuexy-admin/flag-icons/flags/1x1/de.svg') }}" style="height:16px" class="inline" alt="">
|
||||
<span class="ml-1">German</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<!--/ Language -->
|
||||
|
||||
|
||||
@if($configData['hasCustomizer'] == true)
|
||||
<!-- Style Switcher -->
|
||||
<li class="nav-item dropdown-style-switcher dropdown">
|
||||
@ -96,57 +134,23 @@ $navbarDetached = ($navbarDetached ?? '');
|
||||
@endif
|
||||
|
||||
<!-- Quick links -->
|
||||
@if ($vuexyQuickLinks)
|
||||
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown">
|
||||
<a class="nav-link btn btn-text-secondary btn-icon rounded-pill btn-icon dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
|
||||
<i class='ti ti-layout-grid-add ti-md'></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end p-0">
|
||||
<div class="dropdown-menu-header border-bottom">
|
||||
<div class="dropdown-header d-flex align-items-center py-3">
|
||||
<h6 class="mb-0 me-auto">Atajos</h6>
|
||||
@if($vuexyQuickLinks['current_page_in_list'])
|
||||
<a href="javascript:void(0)" class="btn btn-text-secondary rounded-pill btn-icon dropdown-shortcuts-remove" data-bs-toggle="tooltip" data-bs-placement="top" title="Remover atajo"><i class="ti ti-trash text-heading"></i></a>
|
||||
@else
|
||||
@if($vuexyQuickLinks['totalLinks'] < config('vuexy.custom.maxQuickLinks'))
|
||||
<a href="javascript:void(0)" class="btn btn-text-secondary rounded-pill btn-icon dropdown-shortcuts-add" data-bs-toggle="tooltip" data-bs-placement="top" title="Agregar atajo"><i class="ti ti-plus text-heading"></i></a>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-shortcuts-list scrollable-container">
|
||||
@foreach ($vuexyQuickLinks['rows'] as $quickLinksRow)
|
||||
<div class="row row-bordered overflow-visible g-0">
|
||||
@foreach ($quickLinksRow as $key => $quickLink)
|
||||
<div class="dropdown-shortcuts-item col @if($quickLink['route'] === Route::currentRouteName()) active @endif">
|
||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i class="ti ti-{{ $quickLink['icon'] }} ti-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="{{ $quickLink['url'] }}" class="stretched-link">{{ $quickLink['title'] }}</a>
|
||||
<small>{{ $quickLink['subtitle'] }}</small>
|
||||
</div>
|
||||
@if ($key == 0 && !isset($quickLinksRow[1]))
|
||||
<div class="dropdown-shortcuts-item col"></div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endif
|
||||
@livewire('vuexy-admin::vuexy-quicklinks')
|
||||
<!-- Quick links -->
|
||||
|
||||
<!-- Notification -->
|
||||
{!! $vuexyNotifications !!}
|
||||
@if($vuexyNotifications)
|
||||
@foreach ($vuexyNotifications as $vuexyNotification)
|
||||
|
||||
@endforeach
|
||||
@endif
|
||||
<!--/ Notification -->
|
||||
|
||||
<!-- User -->
|
||||
<li class="nav-item navbar-dropdown dropdown-user dropdown">
|
||||
<a class="nav-link dropdown-toggle hide-arrow d-flex align-items-center" href="javascript:void(0);" data-bs-toggle="dropdown">
|
||||
<a class="nav-link dropdown-toggle hide-arrow d-flex align-items-center ml-2" href="javascript:void(0);" data-bs-toggle="dropdown">
|
||||
@if (Auth::check())
|
||||
<div class="user-nav me-2 d-none d-sm-block">
|
||||
<span class="user-name d-block text-end">{{ Auth::user()->fullname }}</span>
|
||||
<span class="user-name d-block text-end">{{ Auth::user()->full_name }}</span>
|
||||
<span class="user-email d-block text-end">{{ Auth::user()->email }}</span>
|
||||
</div>
|
||||
@endif
|
||||
@ -179,14 +183,14 @@ $navbarDetached = ($navbarDetached ?? '');
|
||||
@endif
|
||||
@if (Auth::check())
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ route('admin.core.user-profile.index') }}">
|
||||
<a class="dropdown-item" href="{{ route('admin.core.user.profile.index') }}">
|
||||
<i class="ti ti-user-cog me-2 ti-sm"></i>
|
||||
<span class="align-middle">Cuenta de usuario</span>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li>
|
||||
<a class="dropdown-item" href="{{ route('admin.core.about.index') }}">
|
||||
<a class="dropdown-item" href="{{ route('admin.core.pages.about.index') }}">
|
||||
<i class='ti ti-cat me-2'></i>
|
||||
<span class="align-middle">Acerca de</span>
|
||||
</a>
|
||||
@ -218,14 +222,12 @@ $navbarDetached = ($navbarDetached ?? '');
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@if ($vuexySearch)
|
||||
<!-- Search Small Screens -->
|
||||
<div class="navbar-search-wrapper search-input-wrapper {{ isset($menuHorizontal) ? $containerNav : '' }} d-none">
|
||||
<input type="text" class="form-control search-input {{ isset($menuHorizontal) ? '' : $containerNav }} border-0" placeholder="Buscar..." aria-label="Buscar...">
|
||||
<i class="ti ti-x search-toggler cursor-pointer"></i>
|
||||
</div>
|
||||
<!--/ Search Small Screens -->
|
||||
@endif
|
||||
<!-- Search Small Screens -->
|
||||
<div class="navbar-search-wrapper search-input-wrapper {{ isset($menuHorizontal) ? $containerNav : '' }} d-none">
|
||||
<input type="text" class="form-control search-input {{ isset($menuHorizontal) ? '' : $containerNav }} border-0" placeholder="Search..." aria-label="Search...">
|
||||
<i class="ti ti-x search-toggler cursor-pointer"></i>
|
||||
</div>
|
||||
<!--/ Search Small Screens -->
|
||||
@if(isset($navbarDetached) && $navbarDetached == '')
|
||||
</div>
|
||||
@endif
|
||||
|
@ -0,0 +1,26 @@
|
||||
@php
|
||||
$notifications = collect([
|
||||
session('vuexy_notification') ? ['channel' => 'vuexy', 'data' => session('vuexy_notification')] : null,
|
||||
session('vuexy_toastr') ? ['channel' => 'toastr', 'data' => session('vuexy_toastr')] : null,
|
||||
session('vuexy_notyf') ? ['channel' => 'notyf', 'data' => session('vuexy_notyf')] : null,
|
||||
session('vuexy_swal') ? ['channel' => 'sweetalert', 'data' => session('vuexy_swal')] : null,
|
||||
session('vuexy_pnotify') ? ['channel' => 'pnotify', 'data' => session('vuexy_pnotify')] : null,
|
||||
])->filter();
|
||||
@endphp
|
||||
|
||||
@if ($notifications->isNotEmpty())
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', async function () {
|
||||
const notifications = @json($notifications);
|
||||
|
||||
for (const n of notifications) {
|
||||
try {
|
||||
const { NotifyChannelService } = await import('/build/js/notify-channel-service.js');
|
||||
await NotifyChannelService.notify({ channel: n.channel, ...n.data });
|
||||
} catch (e) {
|
||||
console.error('❌ Error al enviar notificación por canal: ' + n.channel, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endif
|
@ -2,19 +2,22 @@
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/jquery/jquery.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/popper/popper.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/toastr/toastr.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/notyf/notyf.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/js/bootstrap.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/node-waves/node-waves.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/hammer/hammer.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/typeahead-js/typeahead.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/js/menu.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/notifications/notify-loader.js'
|
||||
])
|
||||
|
||||
@yield('vendor-script')
|
||||
<!-- END: Page Vendor JS-->
|
||||
|
||||
<!-- BEGIN: Theme JS-->
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/assets/js/main.js')
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/assets/js/layout/main.js')
|
||||
<!-- END: Theme JS-->
|
||||
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/js/app.js')
|
||||
|
@ -0,0 +1,79 @@
|
||||
@php
|
||||
$menuCollapsed = ($configData['menuCollapsed'] === 'layout-menu-collapsed') ? json_encode(true) : false;
|
||||
@endphp
|
||||
|
||||
<!-- Laravel Helper Functions -->
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/js/helpers.js')
|
||||
|
||||
@if ($configData['hasCustomizer'])
|
||||
<!--! Template customizer & Theme config files -->
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/js/template-customizer.js')
|
||||
@endif
|
||||
|
||||
<!-- Config File -->
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/assets/js/config.js')
|
||||
|
||||
<!-- Notificaciones Vuexy (alerts tipo Bootstrap) -->
|
||||
@if (session('vuexy_notification'))
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const notification = @json(session('vuexy_notification'));
|
||||
|
||||
if (window.vuexyNotify) {
|
||||
window.vuexyNotify.flash(notification);
|
||||
|
||||
} else {
|
||||
console.warn('⚠️ VuexyNotify no encontrado');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
<!-- Notificaciones Toastr (tipo push) -->
|
||||
@if (session('vuexy_toastr'))
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const toastrData = @json(session('vuexy_toastr'));
|
||||
|
||||
if (window.toastr) {
|
||||
toastr.options.timeOut = toastrData.delay || 5000;
|
||||
toastr.options.positionClass = "toast-top-right";
|
||||
toastr[toastrData.type](toastrData.message);
|
||||
|
||||
} else {
|
||||
console.warn('⚠️ Toastr no encontrado');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endif
|
||||
|
||||
@if ($configData['hasCustomizer'])
|
||||
<script type="module">
|
||||
window.templateCustomizer = new TemplateCustomizer({
|
||||
cssPath: '',
|
||||
themesPath: '',
|
||||
defaultStyle: "{{ $configData['styleOpt'] }}",
|
||||
defaultShowDropdownOnHover: "{{ $configData['showDropdownOnHover'] }}", // true/false (for horizontal layout only)
|
||||
displayCustomizer: "{{ $configData['displayCustomizer'] }}",
|
||||
lang: '{{ app()->getLocale() }}',
|
||||
pathResolver: function(path) {
|
||||
var resolvedPaths = {
|
||||
// Core stylesheets
|
||||
@foreach (['core'] as $name)
|
||||
'{{ $name }}.scss': '{{ Vite::asset('vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/scss'.$configData["rtlSupport"].'/'.$name.'.scss') }}',
|
||||
'{{ $name }}-dark.scss': '{{ Vite::asset('vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/scss'.$configData["rtlSupport"].'/'.$name.'-dark.scss') }}',
|
||||
@endforeach
|
||||
|
||||
// Themes
|
||||
@foreach (['default', 'bordered', 'semi-dark'] as $name)
|
||||
'theme-{{ $name }}.scss': '{{ Vite::asset('vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/scss'.$configData["rtlSupport"].'/theme-'.$name.'.scss') }}',
|
||||
'theme-{{ $name }}-dark.scss': '{{ Vite::asset('vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/scss'.$configData["rtlSupport"].'/theme-'.$name.'-dark.scss') }}',
|
||||
@endforeach
|
||||
};
|
||||
|
||||
return resolvedPaths[path] || path;
|
||||
},
|
||||
'controls': <?php echo json_encode($configData['customizerControls']); ?>,
|
||||
});
|
||||
</script>
|
||||
@endif
|
@ -11,7 +11,7 @@
|
||||
@endif
|
||||
|
||||
<!-- Config File -->
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/assets/js/config.js')
|
||||
@vite('vendor/koneko/laravel-vuexy-admin/resources/assets/js/layout/config.js')
|
||||
|
||||
@if ($configData['hasCustomizer'])
|
||||
<script type="module">
|
||||
|
@ -5,7 +5,6 @@
|
||||
<link href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet">
|
||||
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/tabler-icons.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/fontawesome.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/node-waves/node-waves.scss',
|
||||
])
|
||||
@ -22,6 +21,7 @@
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/typeahead-js/typeahead.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/toastr/toastr.scss',
|
||||
])
|
||||
|
||||
@yield('vendor-style')
|
||||
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" />
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" />
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" />
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<p>Module Management</p>
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<p>Plugins</p>
|
||||
</div>
|
83
resources/views/livewire/navbar/vuexy-quicklinks.blade.php
Normal file
83
resources/views/livewire/navbar/vuexy-quicklinks.blade.php
Normal file
@ -0,0 +1,83 @@
|
||||
<li class="nav-item dropdown-shortcuts navbar-dropdown dropdown">
|
||||
<a class="nav-link btn btn-text-secondary btn-icon rounded-pill btn-icon dropdown-toggle hide-arrow" href="javascript:void(0);" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
|
||||
<i class='ti ti-layout-grid-add ti-md'></i>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end p-0">
|
||||
<div class="dropdown-menu-header border-bottom">
|
||||
<div class="dropdown-header d-flex align-items-center py-3">
|
||||
<h6 class="mb-0 me-auto">Atajos</h6>
|
||||
@if($isRouteAllowed)
|
||||
@if($vuexyQuickLinks['current_page_in_list'])
|
||||
<button
|
||||
wire:click="remove('{{ Route::currentRouteName() }}')"
|
||||
type="button"
|
||||
class="btn btn-text-secondary rounded-pill btn-icon dropdown-shortcuts-remove"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Remover atajo">
|
||||
<i class="ti ti-trash text-heading"></i>
|
||||
</button>
|
||||
@else
|
||||
@if($vuexyQuickLinks['totalLinks'] < config('koneko.admin.vuexy.maxQuickLinks', 8))
|
||||
<button
|
||||
wire:click="add('{{ Route::currentRouteName() }}')"
|
||||
type="button"
|
||||
class="btn btn-text-secondary rounded-pill btn-icon dropdown-shortcuts-add"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Agregar atajo">
|
||||
<i class="ti ti-plus text-heading"></i>
|
||||
</button>
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown-shortcuts-list scrollable-container">
|
||||
@foreach ($vuexyQuickLinks['rows'] as $quickLinksRow)
|
||||
<div class="row row-bordered overflow-visible g-0">
|
||||
@foreach ($quickLinksRow as $key => $quickLink)
|
||||
<div class="dropdown-shortcuts-item col @if ($quickLink['route'] === $currentRouteId) active @endif">
|
||||
<span class="dropdown-shortcuts-icon rounded-circle mb-3">
|
||||
<i class="ti ti-{{ $quickLink['icon'] }} ti-26px text-heading"></i>
|
||||
</span>
|
||||
<a href="{{ $quickLink['url'] }}" class="stretched-link">{{ $quickLink['title'] }}</a>
|
||||
<small>{{ $quickLink['subtitle'] }}</small>
|
||||
</div>
|
||||
@if ($key == 0 && !isset($quickLinksRow[1]))
|
||||
<div class="dropdown-shortcuts-item col"></div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.addEventListener('refresh-tooltips', () => {
|
||||
initVuexyTooltips();
|
||||
|
||||
setTimeout(() => {
|
||||
window.Helpers.initNavbarDropdownScrollbar();
|
||||
}, 1);
|
||||
});
|
||||
|
||||
function initVuexyTooltips() {
|
||||
// Limpia tooltips previos
|
||||
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
|
||||
|
||||
tooltipTriggerList.forEach(el => {
|
||||
const tooltip = bootstrap.Tooltip.getInstance(el);
|
||||
|
||||
if (tooltip) {
|
||||
tooltip.dispose(); // elimina instancia previa
|
||||
}
|
||||
});
|
||||
|
||||
// Vuelve a inicializar
|
||||
tooltipTriggerList.forEach(el => {
|
||||
new bootstrap.Tooltip(el);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,207 @@
|
||||
@php
|
||||
/**
|
||||
* Vista Blade para mostrar los accesos rápidos.
|
||||
* Compatible con Vuexy Admin y modo oscuro.
|
||||
*/
|
||||
@endphp
|
||||
|
||||
<div class="space-y-8">
|
||||
<!-- 🔍 Campo de búsqueda -->
|
||||
<x-vuexy-admin::form.input
|
||||
id="quick_acces_search"
|
||||
placeholder="Buscar acceso rápido..."
|
||||
suffixIcon="ti ti-search"
|
||||
class="form-control-lg"
|
||||
mb0
|
||||
autocomplete="off"
|
||||
role="search"
|
||||
aria-label="Buscar acceso rápido"
|
||||
/>
|
||||
@if($components)
|
||||
<div class="col-12 overflow-hidden mt-2">
|
||||
<div id="quick-access-scroll">
|
||||
<ul class="nav mb-1" id="quick-access-tabs">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link active" data-component-filter="all">Todos</button>
|
||||
</li>
|
||||
@foreach($components as $component)
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-component-filter="{{ $component['namespace'] }}">
|
||||
{{ \Str::headline($component['label']) }}
|
||||
</button>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@foreach ($menuCards as $category)
|
||||
@if(!empty($category['cards']) || config('vuexy.debug.menu.show_all_hidden', false))
|
||||
<div class="quick-access-category">
|
||||
<!-- Título de categoría con icono -->
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="{{ $category['icon'] }} text-2xl text-primary"></i>
|
||||
<h5 class="mb-0 ms-2 text-dark dark:text-white search-term">{{ $category['title'] }}</h5>
|
||||
</div>
|
||||
<!-- Descripción de categoría -->
|
||||
@if (!empty($category['description']))
|
||||
<p class="text-muted">
|
||||
{{ $category['description'] }}
|
||||
</p>
|
||||
@endif
|
||||
<!-- Grid de accesos rápidos en formato de Cards -->
|
||||
@if (!empty($category['cards']))
|
||||
<div class="row row-cols-2 row-cols-md-4 row-cols-lg-5 g-4">
|
||||
@foreach ($category['cards'] as $item)
|
||||
<div class="col quick-access-card" data-component="{{ $item['component'] ?? 'unknown' }}">
|
||||
<a href="{{ $item['url'] }}" class="text-decoration-none">
|
||||
<div class="card border-0 shadow-sm hover:shadow-lg transition-all duration-300">
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center text-center p-4">
|
||||
<!-- Ícono -->
|
||||
<i class="{{ $item['icon'] }} text-3xl text-primary mt-1 mb-3"></i>
|
||||
|
||||
<!-- Título -->
|
||||
<h6 class="mb-0 text-dark dark:text-light fw-semibold search-term">
|
||||
{{ $item['title'] }}
|
||||
@if(config('koneko.admin.menu.debug.show_broken_routers') && $item['url'] == "javascript:;")
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="xs mr-1">❌</span>
|
||||
Sin URL valida
|
||||
</p>
|
||||
@endif
|
||||
@if(config('koneko.admin.menu.debug.show_disallowed_links') && $item['disallowed_link'])
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="text-sm mr-1">🔒</span>
|
||||
Sin permisos
|
||||
</p>
|
||||
@endif
|
||||
@if(config('koneko.admin.menu.debug.show_hidden_items') && $item['hidden_item'])
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="text-sm mr-1">🚧</span>
|
||||
Vista forzada
|
||||
</p>
|
||||
@endif
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<p class="text-muted fst-italic">
|
||||
No hay accesos rápidos en esta categoría.
|
||||
</p>
|
||||
@endif
|
||||
<div class="pb-6"></div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const quickAccessScroll = document.getElementById('quick-access-scroll');
|
||||
const searchInput = document.getElementById('quick_acces_search');
|
||||
const categories = document.querySelectorAll('.quick-access-category');
|
||||
const tabButtons = document.querySelectorAll('#quick-access-tabs button');
|
||||
const normalize = str => str?.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||
|
||||
const highlightMatch = (element, term) => {
|
||||
const text = element.dataset.originalText || element.textContent;
|
||||
|
||||
element.dataset.originalText = text; // Save original
|
||||
|
||||
if (!term) {
|
||||
element.innerHTML = text;
|
||||
return;
|
||||
}
|
||||
|
||||
const regex = new RegExp(`(${term})`, 'gi');
|
||||
|
||||
element.innerHTML = text.replace(regex, '<mark>$1</mark>');
|
||||
};
|
||||
|
||||
let currentComponentFilter = 'all';
|
||||
|
||||
|
||||
// PerfectScroll
|
||||
if (quickAccessScroll) {
|
||||
new PerfectScrollbar(quickAccessScroll, {
|
||||
suppressScrollY: true,
|
||||
wheelPropagation: false
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Buscador
|
||||
searchInput.focus();
|
||||
searchInput.addEventListener('input', applyFilters);
|
||||
|
||||
|
||||
// Tabs
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', function () {
|
||||
currentComponentFilter = this.dataset.componentFilter;
|
||||
|
||||
tabButtons.forEach(b => b.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
|
||||
applyFilters();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Método de filtrado
|
||||
function applyFilters() {
|
||||
const searchTerm = normalize(searchInput.value.trim());
|
||||
const isSearchEmpty = searchTerm === '';
|
||||
|
||||
categories.forEach(category => {
|
||||
let categoryMatch = false;
|
||||
const categoryTitleEl = category.querySelector('.search-term');
|
||||
const categoryTitle = normalize(categoryTitleEl?.textContent);
|
||||
const categoryMatches = categoryTitle.includes(searchTerm);
|
||||
|
||||
highlightMatch(categoryTitleEl, searchTerm);
|
||||
|
||||
const cards = category.querySelectorAll('.quick-access-card');
|
||||
let visibleCards = 0;
|
||||
|
||||
cards.forEach(card => {
|
||||
const titleEl = card.querySelector('.search-term');
|
||||
const titleText = normalize(titleEl?.textContent);
|
||||
const cardComponent = card.dataset.component;
|
||||
|
||||
const matchesComponent = currentComponentFilter === 'all' || cardComponent === currentComponentFilter;
|
||||
const matchesSearch = isSearchEmpty || titleText.includes(searchTerm) || categoryMatches;
|
||||
|
||||
const match = matchesComponent && matchesSearch;
|
||||
|
||||
highlightMatch(titleEl, searchTerm);
|
||||
|
||||
if (match) {
|
||||
card.classList.remove('quick-hidden');
|
||||
card.style.display = 'block';
|
||||
requestAnimationFrame(() => {
|
||||
card.classList.add('quick-showing');
|
||||
});
|
||||
visibleCards++;
|
||||
} else {
|
||||
card.classList.remove('quick-showing');
|
||||
card.classList.add('quick-hidden');
|
||||
setTimeout(() => {
|
||||
card.style.display = 'none';
|
||||
}, 400);
|
||||
}
|
||||
});
|
||||
|
||||
const showCategory = visibleCards > 0;
|
||||
|
||||
category.classList.toggle('quick-hidden', !showCategory);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,155 @@
|
||||
@php
|
||||
/**
|
||||
* Vista Blade para mostrar los accesos rápidos.
|
||||
* Compatible con Vuexy Admin y modo oscuro.
|
||||
*/
|
||||
@endphp
|
||||
|
||||
<div class="space-y-8">
|
||||
<!-- 🔍 Campo de búsqueda -->
|
||||
<x-vuexy-admin::form.input
|
||||
id="quick_acces_search"
|
||||
placeholder="Buscar acceso rápido..."
|
||||
suffixIcon="ti ti-search"
|
||||
class="form-control-lg"
|
||||
mb0
|
||||
autocomplete="off"
|
||||
role="search"
|
||||
aria-label="Buscar acceso rápido"
|
||||
/>
|
||||
@if($components)
|
||||
<div class="col-12 overflow-hidden mt-2">
|
||||
<div id="quick-access-scroll">
|
||||
<ul class="nav mb-1" id="quick-access-tabs">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link active" data-component-filter="all">Todos</button>
|
||||
</li>
|
||||
@foreach($components as $component)
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-component-filter="{{ $component['tag'] }}">
|
||||
{{ $component['label'] }}
|
||||
</button>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@foreach ($groups as $group)
|
||||
@if(!empty($group['cards']))
|
||||
<div class="quick-access-group">
|
||||
<!-- Título de categoría con icono -->
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="{{ $group['icon'] }} text-2xl text-primary"></i>
|
||||
<h5 class="mb-0 ms-2 text-dark dark:text-white search-term">{{ $group['label'] }}</h5>
|
||||
</div>
|
||||
<!-- Descripción de categoría -->
|
||||
@if (!empty($group['description']))
|
||||
<p class="text-muted">
|
||||
{{ $group['description'] }}
|
||||
</p>
|
||||
@endif
|
||||
<!-- Grid de accesos rápidos en formato de Cards -->
|
||||
<div class="row row-cols-2 row-cols-md-4 row-cols-lg-5 g-4">
|
||||
@foreach ($group['cards'] as $item)
|
||||
<div class="col quick-access-card" data-component="{{ $item['component'] ?? 'unknown' }}">
|
||||
<a href="{{ $item['url'] }}" class="text-decoration-none">
|
||||
<div class="card border-0 shadow-sm hover:shadow-lg transition-all duration-300">
|
||||
<div class="card-body d-flex flex-column align-items-center justify-content-center text-center p-4">
|
||||
<i class="{{ $item['icon'] }} text-3xl text-primary mt-1 mb-3"></i>
|
||||
<h6 class="mb-0 text-dark dark:text-light fw-semibold search-term">
|
||||
{{ $item['title'] }}
|
||||
@if(config('koneko.admin.menu.debug.show_broken_routers') && $item['url'] == "javascript:;")
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="xs mr-1">❌</span> Sin URL válida
|
||||
</p>
|
||||
@endif
|
||||
@if(config('koneko.admin.menu.debug.show_disallowed_links') && $item['disallowed_link'])
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="text-sm mr-1">🔒</span> Sin permisos
|
||||
</p>
|
||||
@endif
|
||||
@if(config('koneko.admin.menu.debug.show_hidden_items') && $item['hidden_item'])
|
||||
<p class="text-xs m-0 pt-2 text-gray-500">
|
||||
<span class="text-sm mr-1">🚧</span> Vista forzada
|
||||
</p>
|
||||
@endif
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="pb-6"></div>
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const searchInput = document.getElementById('quick_acces_search');
|
||||
const categories = document.querySelectorAll('.quick-access-group');
|
||||
const tabButtons = document.querySelectorAll('#quick-access-tabs button');
|
||||
const normalize = str => str?.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||
|
||||
const highlightMatch = (element, term) => {
|
||||
const text = element.dataset.originalText || element.textContent;
|
||||
element.dataset.originalText = text;
|
||||
element.innerHTML = term ? text.replace(new RegExp(`(${term})`, 'gi'), '<mark>$1</mark>') : text;
|
||||
};
|
||||
|
||||
let currentComponentFilter = 'all';
|
||||
|
||||
searchInput.focus();
|
||||
searchInput.addEventListener('input', applyFilters);
|
||||
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', function () {
|
||||
currentComponentFilter = this.dataset.componentFilter;
|
||||
tabButtons.forEach(b => b.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
applyFilters();
|
||||
});
|
||||
});
|
||||
|
||||
function applyFilters() {
|
||||
const searchTerm = normalize(searchInput.value.trim());
|
||||
const isSearchEmpty = searchTerm === '';
|
||||
|
||||
categories.forEach(group => {
|
||||
const groupTitleEl = group.querySelector('.search-term');
|
||||
const groupTitle = normalize(groupTitleEl?.textContent);
|
||||
const groupMatches = groupTitle.includes(searchTerm);
|
||||
|
||||
highlightMatch(groupTitleEl, searchTerm);
|
||||
|
||||
const cards = group.querySelectorAll('.quick-access-card');
|
||||
|
||||
let visibleCards = 0;
|
||||
|
||||
cards.forEach(card => {
|
||||
const titleEl = card.querySelector('.search-term');
|
||||
const titleText = normalize(titleEl?.textContent);
|
||||
const cardComponent = card.dataset.component;
|
||||
|
||||
const matchesComponent = currentComponentFilter === 'all' || cardComponent === currentComponentFilter;
|
||||
const matchesSearch = isSearchEmpty || titleText.includes(searchTerm) || groupMatches;
|
||||
|
||||
const match = matchesComponent && matchesSearch;
|
||||
|
||||
highlightMatch(titleEl, searchTerm);
|
||||
|
||||
card.classList.toggle('quick-hidden', !match);
|
||||
card.style.display = match ? 'block' : 'none';
|
||||
if (match) visibleCards++;
|
||||
});
|
||||
|
||||
group.classList.toggle('quick-hidden', visibleCards === 0);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -1,7 +0,0 @@
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable">
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-offcanvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
@ -9,7 +9,7 @@
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="key" label="Clave del parámetro" required icon="ti ti-key" placeholder="Ej: ui.theme" />
|
||||
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="category" label="Categoría"
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="module" label="Categoría"
|
||||
:options="[
|
||||
'general' => 'General',
|
||||
'ui' => 'Interfaz',
|
@ -0,0 +1,9 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable">
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-offcanvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
||||
</div>
|
@ -2,9 +2,9 @@
|
||||
changeSmtpSettings: @entangle('change_smtp_settings'),
|
||||
saveButtonDisabled: @entangle('save_button_disabled'),
|
||||
}">
|
||||
<form id="sendmail-settings-card">
|
||||
<form id="smtp-settings-card">
|
||||
<div class="card mb-6">
|
||||
<h5 class="card-header">Servidor saliente de correo electrónico</h5>
|
||||
<h5 class="card-header">Servidor de correo saliente</h5>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<x-vuexy-admin::form.checkbox
|
45
resources/views/livewire/settings/users/form.blade.php
Normal file
45
resources/views/livewire/settings/users/form.blade.php
Normal file
@ -0,0 +1,45 @@
|
||||
<div>
|
||||
<x-vuexy-admin::form id="{{ $formId }}" :mode="$mode" wireSubmit="onSubmit" actionPosition="both">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.form-buttons :mode="$mode" :label="$singularName" />
|
||||
</x-slot>
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
{{-- Identificación --}}
|
||||
<x-vuexy-admin::card.basic title="Identificación">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre de usuario" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Configuraciones --}}
|
||||
<x-vuexy-admin::card.basic title="Configuraciones">
|
||||
<x-vuexy-admin::form.checkbox uid="random" model="status" label="Habilitar sucursal" switch="true" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
{{-- Información de contacto --}}
|
||||
<x-vuexy-admin::card.basic title="Información de contacto">
|
||||
<x-vuexy-admin::form.input type="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
</div>
|
||||
</x-vuexy-admin::form>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const initializeUserForm = (mode) => {
|
||||
|
||||
}
|
||||
|
||||
// Evento para inicializar el formulario
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.addEventListener('on-failed-validation-user', (event) => {
|
||||
setTimeout(() => {
|
||||
initializeUserForm('{{ $mode }}');
|
||||
}, 10);
|
||||
});
|
||||
|
||||
initializeUserForm('{{ $mode }}');
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,93 @@
|
||||
<div>
|
||||
<x-vuexy-admin::offcanvas.basic :id="$offcanvasId" :tag-name="$tagName">
|
||||
<x-vuexy-admin::form :uid="$uniqueId" :id="$formId" :mode="$mode" wireSubmit="onSubmit">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.offcanvas-buttons :mode="$mode" :tagName="$tagName" />
|
||||
</x-slot>
|
||||
{{-- Usuario --}}
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre(s)" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="last_name" label="Apellidos" />
|
||||
{{-- Correos electrónicos --}}
|
||||
<x-vuexy-admin::form.input type="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
|
||||
{{-- Imágen de perfil --}}
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Imágen de perfil</label>
|
||||
@if ($upload_profile_photo && in_array($upload_profile_photo->getMimeType(), ['image/jpeg', 'image/png', 'image/webp']))
|
||||
<div class="text-center mb-2">
|
||||
<img src="{{ $upload_profile_photo->temporaryUrl() }}" alt="Vista previa" class="img-thumbnail mx-auto" style="max-height: 300px;">
|
||||
</div>
|
||||
@endif
|
||||
<x-vuexy-admin::form.input type="file" :uid="$uniqueId" model="upload_profile_photo" accept="image/*" />
|
||||
</div>
|
||||
|
||||
{{-- Contraseña --}}
|
||||
<x-vuexy-admin::form.input-password :uid="$uniqueId" model="password" icon="ti ti-lock" />
|
||||
|
||||
{{-- Roles --}}
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="roles" label="Roles" multiple :options="$rolesOptions" class="select2 form-select" />
|
||||
<hr>
|
||||
</x-vuexy-admin::form>
|
||||
</x-vuexy-admin::offcanvas.basic>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const uniqueId = '{{ $uniqueId }}';
|
||||
const offcanvasId = '{{ $offcanvasId }}';
|
||||
const tagName = '{{ Str::kebab($tagName) }}';
|
||||
const myOffcanvas = document.getElementById(offcanvasId);
|
||||
|
||||
// Asegúrate de no agregar múltiples veces el listener
|
||||
const hideAndReopen = () => {
|
||||
let myOffcanvas = document.getElementById(offcanvasId);
|
||||
let offcanvasInstance = bootstrap.Offcanvas.getOrCreateInstance(myOffcanvas);
|
||||
|
||||
const onHidden = () => {
|
||||
myOffcanvas.removeEventListener('hidden.bs.offcanvas', onHidden);
|
||||
offcanvasInstance.show();
|
||||
};
|
||||
|
||||
myOffcanvas.addEventListener('hidden.bs.offcanvas', onHidden);
|
||||
offcanvasInstance.hide();
|
||||
};
|
||||
|
||||
// Inizar Select2
|
||||
const initializeSelect2 = () => {
|
||||
let rolesSelect = document.getElementById(`roles_${uniqueId}`),
|
||||
myOffcanvas = document.getElementById(offcanvasId);
|
||||
|
||||
$(rolesSelect)
|
||||
.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
placeholder: 'Selecciona los roles',
|
||||
dropdownParent: myOffcanvas
|
||||
})
|
||||
.on('select2:clear', () => {
|
||||
@this.roles = [];
|
||||
})
|
||||
.on('select2:select', (e) => {
|
||||
@this.roles.push(e.params.data.id);
|
||||
});
|
||||
};
|
||||
|
||||
// Inicializar el formulario
|
||||
const initializeUserForm = () => {
|
||||
setTimeout(initializeSelect2, 10);
|
||||
};
|
||||
|
||||
|
||||
// Evento para inicializar el formulario cuando se abre el offcanvas
|
||||
myOffcanvas.addEventListener('show.bs.offcanvas', function () {
|
||||
initializeUserForm();
|
||||
attachPasswordToggles();
|
||||
});
|
||||
|
||||
|
||||
// Evento para recargar el formulario
|
||||
Livewire.on('refresh-user-form', hideAndReopen);
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -42,7 +42,7 @@
|
||||
<i class="ti ti-user pr-2"></i> Cuenta de usuario
|
||||
</button>
|
||||
</li>
|
||||
@if (($is_customer) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_customer) && $this->tipo_persona != Koneko\VuexyAdmin\Models\User::TIPO_RFC_PUBLICO)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" @click="setActiveTabPan('accesos')" :class="{ 'active': activeTabPan === 'accesos' }" class="nav-link waves-effect" role="tab" data-bs-toggle="tab" data-bs-target="#navs-left-accesos" aria-controls="navs-left-accesos">
|
||||
<i class="ti ti-key pr-2"></i> Accesos
|
||||
@ -56,21 +56,21 @@
|
||||
</button>
|
||||
</li>
|
||||
@endif
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != Koneko\VuexyAdmin\Models\User::TIPO_RFC_PUBLICO)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" @click="setActiveTabPan('direcciones')" :class="{ 'active': activeTabPan === 'direcciones' }" class="nav-link waves-effect" role="tab" data-bs-toggle="tab" data-bs-target="#navs-left-direcciones" aria-controls="navs-left-direcciones">
|
||||
<i class="ti ti-map-pin pr-2"></i> Direcciones
|
||||
</button>
|
||||
</li>
|
||||
@endif
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_prospect || $is_customer || $is_provider) && $this->tipo_persona != Koneko\VuexyAdmin\Models\User::TIPO_RFC_PUBLICO)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" @click="setActiveTabPan('contacto')" :class="{ 'active': activeTabPan === 'contacto' }" class="nav-link waves-effect" role="tab" data-bs-toggle="tab" data-bs-target="#navs-left-contacto" aria-controls="navs-left-contacto">
|
||||
<i class="ti ti-address-book pr-2"></i> Contacto
|
||||
</button>
|
||||
</li>
|
||||
@endif
|
||||
@if (($is_customer || $is_provider) && $this->tipo_persona != App\Models\User::TIPO_RFC_PUBLICO)
|
||||
@if (($is_customer || $is_provider) && $this->tipo_persona != Koneko\VuexyAdmin\Models\User::TIPO_RFC_PUBLICO)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" @click="setActiveTabPan('cuentas-bancarias')" :class="{ 'active': activeTabPan === 'cuentas-bancarias' }" class="nav-link waves-effect" role="tab" data-bs-toggle="tab" data-bs-target="#navs-left-cuentas-bancarias" aria-controls="navs-left-cuentas-bancarias">
|
||||
<i class="ti ti-credit-card pr-2"></i> Cuentas bancarias
|
@ -0,0 +1,15 @@
|
||||
<div>
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" >
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-offcanvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
window.userRoleStyles = {!! $userRoleStyles !!};
|
||||
</script>
|
||||
@endpush
|
@ -1,5 +1,8 @@
|
||||
<div x-data>
|
||||
<div id="interface-settings-card" class="form-custom-listener mb-4">
|
||||
<div id="vuexy-interface-index-card" class="form-custom-listener mb-4">
|
||||
{{-- Notificaciones --}}
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{{-- Tema --}}
|
||||
@ -59,11 +62,32 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-end">
|
||||
<x-vuexy-admin::button.basic wire:click="save" disabled variant="primary" icon="ti ti-check" label="Aplicar cambios" class="btn-save mb-2 mx-2" size="sm" waves />
|
||||
<x-vuexy-admin::button.basic wire:click="resetForm" disabled variant="secondary" icon="ti ti-rotate-2" label="Cancelar" class="btn-cancel mb-2 mx-2" size="sm" waves />
|
||||
<x-vuexy-admin::button.basic wire:click="loadForm" disabled variant="secondary" icon="ti ti-rotate-2" label="Cancelar" class="btn-cancel mb-2 mx-2" size="sm" waves />
|
||||
</div>
|
||||
<div class="col-lg-12 text-end">
|
||||
<x-vuexy-admin::button.basic wire:click="clearCustomConfig" variant="success" icon="ti ti-adjustments-cog" label="Restaurar valores predeterminados" class="btn-reset mb-2 mx-2" size="sm" waves />
|
||||
</div>
|
||||
</div>
|
||||
{{-- Notificaciones --}}
|
||||
<div class="notification-container pt-4" wire:ignore></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
Livewire.on('refreshAndNotify', event => {
|
||||
const notification = {
|
||||
type: event.type || 'success',
|
||||
message: event.message || 'Configuraciones guardadas exitosamente.',
|
||||
target: event.target || '#vuexy-interface-index-card .notification-container',
|
||||
delay: event.delay || 6000
|
||||
};
|
||||
|
||||
// Guardar notificación en localStorage
|
||||
localStorage.setItem('vuexy_notification', JSON.stringify(notification));
|
||||
|
||||
// Refrescar la página
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div id="app-description-settings-card" class="form-custom-listener mb-4">
|
||||
<div id="app-description-card-card" class="form-custom-listener mb-4">
|
||||
<x-vuexy-admin::card.basic title="Datos de la aplicación" class="mb-4">
|
||||
<x-vuexy-admin::form.input
|
||||
label="Titulo de la aplicación"
|
||||
@ -31,7 +31,7 @@
|
||||
icon="ti ti-rotate-2"
|
||||
label="Cancelar"
|
||||
disabled
|
||||
wire:click="resetForm"
|
||||
wire:click="loadForm"
|
||||
class="btn-cancel"
|
||||
waves />
|
||||
</div>
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div id="app-favicon-settings-card" class="mb-4">
|
||||
<div id="app-favicon-card-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Favicon" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
@ -73,7 +73,7 @@
|
||||
size="sm"
|
||||
icon="ti ti-rotate-2"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
wire:click="loadForm"
|
||||
:disabled="$upload_image_favicon === null"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div id="logo-on-dark-bg-settings-card" class="mb-4">
|
||||
<div id="logo-on-dark-bg-card-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Logotipo sobre fondo oscuro" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
@ -29,7 +29,7 @@
|
||||
icon="ti ti-rotate-2"
|
||||
disabled="{{ $upload_image_logo_dark === null }}"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
wire:click="loadForm"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
||||
</div>
|
@ -1,5 +1,5 @@
|
||||
<div>
|
||||
<div id="logo-on-light-bg-settings-card" class="mb-4">
|
||||
<div id="logo-on-light-bg-card-card" class="mb-4">
|
||||
<x-vuexy-admin::card.basic title="Logotipo sobre fondo claro" class="mb-2">
|
||||
<x-vuexy-admin::form.input
|
||||
type="file"
|
||||
@ -29,7 +29,7 @@
|
||||
icon="ti ti-rotate-2"
|
||||
disabled="{{ $upload_image_logo === null }}"
|
||||
label="Cancelar"
|
||||
wire:click="resetForm"
|
||||
wire:click="loadForm"
|
||||
class="btn-cancel mt-2 mr-2"
|
||||
waves />
|
||||
</div>
|
61
resources/views/livewire/user/viewer/index.blade.php
Normal file
61
resources/views/livewire/user/viewer/index.blade.php
Normal file
@ -0,0 +1,61 @@
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<!-- Banner y Header -->
|
||||
<x-vuexy-admin::user.details.banner-profile-header
|
||||
:banner-url="$user?->banner_url"
|
||||
:avatar-url="$user?->profile_photo_url"
|
||||
:name="$user?->name"
|
||||
:position="$user?->position"
|
||||
:location="$user?->location"
|
||||
:joined="$user?->joined_at?->format('F Y')"
|
||||
button-label="Connected"
|
||||
button-icon="ti ti-user-check"
|
||||
/>
|
||||
|
||||
<!-- Tabs -->
|
||||
<x-vuexy-admin::user.details.tabs :tabs="$tabs" />
|
||||
|
||||
<!-- Contenido Principal -->
|
||||
<div class="row">
|
||||
<!-- Columna Izquierda -->
|
||||
<div class="col-xl-4 col-lg-5 col-md-5">
|
||||
<x-vuexy-admin::user.details.about :user="$user" class="mb-6" />
|
||||
@php /*
|
||||
<x-vuexy-admin::user.details.overview :stats="$stats" />
|
||||
*/ @endphp
|
||||
</div>
|
||||
|
||||
<!-- Columna Derecha -->
|
||||
<div class="col-xl-8 col-lg-7 col-md-7">
|
||||
<x-vuexy-admin::user.details.permissions :user="$user" />
|
||||
|
||||
@php /*
|
||||
<x-vuexy-admin::user.details.timeline :items="$timeline" class="mb-6" />
|
||||
*/ @endphp
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-xl-6">
|
||||
@php /*
|
||||
<x-vuexy-admin::user.details.connections :connections="$connections" />
|
||||
*/ @endphp
|
||||
</div>
|
||||
<div class="col-lg-12 col-xl-6">
|
||||
|
||||
@php /*
|
||||
<x-vuexy-admin::user.details.teams :teams="$teams" />
|
||||
*/ @endphp
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
|
||||
tooltipTriggerList.forEach(function (tooltipTriggerEl) {
|
||||
new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user