All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 48s
164 lines
12 KiB
PHP
164 lines
12 KiB
PHP
@extends('layouts.admin')
|
|
|
|
@section('content')
|
|
<div class="space-y-6" x-data="{
|
|
showModal: false,
|
|
isEdit: false,
|
|
roleId: '',
|
|
roleName: '',
|
|
modalTitle: '{{ __('Create Role') }}',
|
|
openModal(edit = false, id = '', name = '') {
|
|
this.isEdit = edit;
|
|
this.roleId = id;
|
|
this.roleName = name;
|
|
this.modalTitle = edit ? '{{ __('Edit Role') }}' : '{{ __('Create Role') }}';
|
|
this.showModal = true;
|
|
}
|
|
}">
|
|
<!-- Header -->
|
|
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
|
|
<div>
|
|
<h1 class="text-3xl font-black text-slate-800 dark:text-white tracking-tight font-display">{{ __('Roles') }}</h1>
|
|
<p class="text-sm font-bold text-slate-500 dark:text-slate-400 mt-1 uppercase tracking-widest">{{ __('Define and manage security roles for the system.') }}</p>
|
|
</div>
|
|
<button @click="openModal()" class="btn-luxury-primary">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
|
|
<span>{{ __('Add Role') }}</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Toolbar -->
|
|
<div class="luxury-card rounded-3xl p-6 mb-6 animate-luxury-in" style="animation-delay: 100ms">
|
|
<div class="flex flex-col md:flex-row md:items-center justify-between gap-6">
|
|
<form action="{{ route('admin.permission.roles') }}" method="GET" class="relative group">
|
|
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none">
|
|
<svg class="h-4 w-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
</svg>
|
|
</span>
|
|
<input type="text" name="search" value="{{ request('search') }}" class="py-2.5 pl-12 pr-6 block w-full md:w-80 luxury-input" placeholder="{{ __('Search roles...') }}">
|
|
</form>
|
|
|
|
<form action="{{ route('admin.permission.roles') }}" method="GET" class="flex items-center gap-3">
|
|
@if(request('search'))<input type="hidden" name="search" value="{{ request('search') }}">@endif
|
|
<label class="text-[11px] font-black text-slate-400 uppercase tracking-widest">{{ __('Show') }}</label>
|
|
<select name="limit" onchange="this.form.submit()" class="luxury-select py-1.5 px-3 text-[11px] min-w-[70px]">
|
|
<option value="10" {{ request('limit') == 10 ? 'selected' : '' }}>10</option>
|
|
<option value="25" {{ request('limit') == 25 ? 'selected' : '' }}>25</option>
|
|
<option value="50" {{ request('limit') == 50 ? 'selected' : '' }}>50</option>
|
|
</select>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Roles List -->
|
|
<div class="luxury-card rounded-3xl p-8 animate-luxury-in" style="animation-delay: 200ms">
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-left border-collapse">
|
|
<thead>
|
|
<tr class="border-b border-slate-100 dark:border-slate-700">
|
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest">{{ __('Role Name') }}</th>
|
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest">{{ __('Type') }}</th>
|
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest text-center">{{ __('Users') }}</th>
|
|
<th class="px-6 py-5 text-sm font-black text-slate-500 dark:text-slate-400 uppercase tracking-widest text-right">{{ __('Actions') }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-50 dark:divide-slate-800">
|
|
@forelse($roles as $role)
|
|
<tr class="hover:bg-slate-50/80 dark:hover:bg-slate-800/50 transition-colors group">
|
|
<td class="px-6 py-5">
|
|
<div class="flex items-center gap-3">
|
|
<span class="text-sm font-bold text-slate-700 dark:text-slate-200">{{ $role->name }}</span>
|
|
@if($role->is_system)
|
|
<span class="p-1.5 bg-cyan-50 dark:bg-cyan-900/30 text-cyan-600 dark:text-cyan-400 rounded-lg tooltip" title="{{ __('System Role') }}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
|
|
</span>
|
|
@endif
|
|
</div>
|
|
</td>
|
|
<td class="px-6 py-5">
|
|
@if($role->is_system)
|
|
<span class="px-2.5 py-1 text-[11px] font-black uppercase tracking-tight bg-slate-100 dark:bg-slate-700 text-slate-500 dark:text-slate-400 rounded-full">
|
|
{{ __('System') }}
|
|
</span>
|
|
@else
|
|
<span class="px-2.5 py-1 text-[11px] font-black uppercase tracking-tight bg-emerald-50 dark:bg-emerald-900/30 text-emerald-600 dark:text-emerald-400 rounded-full">
|
|
{{ __('Custom') }}
|
|
</span>
|
|
@endif
|
|
</td>
|
|
<td class="px-6 py-5 text-center">
|
|
<span class="text-sm font-black text-slate-600 dark:text-slate-400">{{ $role->users_count }}</span>
|
|
</td>
|
|
<td class="px-6 py-5 text-right">
|
|
<div class="flex items-center justify-end gap-2">
|
|
@if(!$role->is_system)
|
|
<button @click="openModal(true, '{{ $role->id }}', '{{ $role->name }}')" class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 transition-all border border-transparent hover:border-cyan-500/20 tooltip" title="{{ __('Edit') }}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4.5 h-4.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>
|
|
</button>
|
|
<form action="{{ route('admin.permission.roles.destroy', $role->id) }}" method="POST" @submit.prevent="if(confirm('{{ __('Are you sure you want to delete this role?') }}')) $el.submit()" class="inline">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="submit" class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-rose-500 hover:bg-rose-500/5 transition-all border border-transparent hover:border-rose-500/20 tooltip" title="{{ __('Delete') }}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4.5 h-4.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" x2="10" y1="11" y2="17"/><line x1="14" x2="14" y1="11" y2="17"/></svg>
|
|
</button>
|
|
</form>
|
|
@else
|
|
<span class="px-3 py-1 text-[11px] font-black uppercase tracking-widest text-slate-400 bg-slate-50 dark:bg-slate-800/50 rounded-lg border border-slate-200/50 dark:border-slate-700/50 italic">{{ __('Protected') }}</span>
|
|
@endif
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="4" class="px-6 py-20 text-center">
|
|
<div class="flex flex-col items-center justify-center gap-4 text-slate-400">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-16 h-16 opacity-20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M12 8v8"/><path d="M8 12h8"/></svg>
|
|
<p class="text-lg font-bold">{{ __('No roles found.') }}</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="mt-8 border-t border-slate-100 dark:border-slate-800 pt-6">
|
|
{{ $roles->links('vendor.pagination.luxury') }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal -->
|
|
<template x-if="showModal">
|
|
<div class="fixed inset-0 z-[60] flex items-center justify-center p-4">
|
|
<div @click="showModal = false" class="absolute inset-0 bg-slate-900/60 backdrop-blur-sm transition-opacity"></div>
|
|
|
|
<div class="relative w-full max-w-lg bg-white dark:bg-slate-900 rounded-2xl shadow-2xl overflow-hidden animate-luxury-in">
|
|
<div class="flex items-center justify-between p-6 border-b border-slate-100 dark:border-slate-800">
|
|
<h3 class="text-xl font-black text-slate-800 dark:text-white" x-text="modalTitle"></h3>
|
|
<button @click="showModal = false" class="text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 transition-colors">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
|
|
</button>
|
|
</div>
|
|
|
|
<form :action="isEdit ? '{{ route('admin.permission.roles') }}/' + roleId : '{{ route('admin.permission.roles.store') }}'" method="POST" class="p-6 space-y-6">
|
|
@csrf
|
|
<template x-if="isEdit"><input type="hidden" name="_method" value="PUT"></template>
|
|
|
|
<div class="space-y-2">
|
|
<label class="text-sm font-black text-slate-700 dark:text-slate-300">{{ __('Role Name') }}</label>
|
|
<input type="text" name="name" x-model="roleName" required class="luxury-input w-full" :placeholder="'{{ __('Enter role name') }}'">
|
|
</div>
|
|
|
|
<div class="flex items-center justify-end gap-3 mt-8">
|
|
<button type="button" @click="showModal = false" class="btn-luxury-ghost px-6 py-2.5 rounded-xl font-bold">{{ __('Cancel') }}</button>
|
|
<button type="submit" class="btn-luxury-primary px-8 py-2.5 rounded-xl font-bold">{{ __('Save Changes') }}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
@endsection
|