Commit 4c209476 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Add full branding settings system with live color theming

- BrandingSettings Livewire component with file uploads (logo, dark logo,
  favicon, signature, login background, invoice header)
- Color picker for primary/secondary/accent/sidebar/status colors with
  live preview panel and preset palettes
- Typography settings (Arabic/English font, base font size)
- Invoice/receipt footer text and terms & conditions
- Display toggles (logo in sidebar, logo in invoice, signature, compact mode)
- CSS variables injected into app layout that drive sidebar, buttons, etc.
- Sidebar now uses --brand-sidebar-bg/text/active variables
- Logo displays in sidebar when uploaded
- SystemSettingsSeeder populates all 6 groups with 50+ settings
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 5fcdb075
<?php
namespace App\Livewire\Settings;
use App\Domain\Shared\Models\Academy;
use App\Domain\Shared\Services\SettingsService;
use Illuminate\Support\Facades\Storage;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Validate;
use Livewire\Component;
use Livewire\WithFileUploads;
#[Layout('layouts.app')]
#[Title('إعدادات الهوية البصرية')]
class BrandingSettings extends Component
{
use WithFileUploads;
// Logo uploads
public $logo;
public $logo_dark;
public $favicon;
public $signature;
public $login_background;
public $invoice_header;
// Current paths
public ?string $current_logo = null;
public ?string $current_logo_dark = null;
public ?string $current_favicon = null;
public ?string $current_signature = null;
public ?string $current_login_background = null;
public ?string $current_invoice_header = null;
// Colors
public string $primary_color = '#2563eb';
public string $secondary_color = '#7c3aed';
public string $accent_color = '#059669';
public string $sidebar_bg = '#0f172a';
public string $sidebar_text = '#e2e8f0';
public string $sidebar_active = '#2563eb';
public string $header_bg = '#ffffff';
public string $success_color = '#10b981';
public string $warning_color = '#f59e0b';
public string $danger_color = '#ef4444';
// Typography
public string $font_family_ar = 'Cairo';
public string $font_family_en = 'Inter';
public string $font_size_base = '14';
// Invoice/Receipt branding
public string $invoice_footer_text = '';
public string $receipt_footer_text = '';
public string $terms_and_conditions = '';
// Display options
public bool $show_logo_in_sidebar = true;
public bool $show_logo_in_invoice = true;
public bool $show_signature_in_invoice = false;
public bool $compact_sidebar = false;
public function mount(): void
{
$this->authorize('settings.manage');
$settings = app(SettingsService::class);
$this->current_logo = $settings->get('branding.logo');
$this->current_logo_dark = $settings->get('branding.logo_dark');
$this->current_favicon = $settings->get('branding.favicon');
$this->current_signature = $settings->get('branding.signature');
$this->current_login_background = $settings->get('branding.login_background');
$this->current_invoice_header = $settings->get('branding.invoice_header');
$this->primary_color = $settings->get('branding.primary_color', '#2563eb');
$this->secondary_color = $settings->get('branding.secondary_color', '#7c3aed');
$this->accent_color = $settings->get('branding.accent_color', '#059669');
$this->sidebar_bg = $settings->get('branding.sidebar_bg', '#0f172a');
$this->sidebar_text = $settings->get('branding.sidebar_text', '#e2e8f0');
$this->sidebar_active = $settings->get('branding.sidebar_active', '#2563eb');
$this->header_bg = $settings->get('branding.header_bg', '#ffffff');
$this->success_color = $settings->get('branding.success_color', '#10b981');
$this->warning_color = $settings->get('branding.warning_color', '#f59e0b');
$this->danger_color = $settings->get('branding.danger_color', '#ef4444');
$this->font_family_ar = $settings->get('branding.font_family_ar', 'Cairo');
$this->font_family_en = $settings->get('branding.font_family_en', 'Inter');
$this->font_size_base = $settings->get('branding.font_size_base', '14');
$this->invoice_footer_text = $settings->get('branding.invoice_footer_text', '');
$this->receipt_footer_text = $settings->get('branding.receipt_footer_text', '');
$this->terms_and_conditions = $settings->get('branding.terms_and_conditions', '');
$this->show_logo_in_sidebar = (bool) $settings->get('branding.show_logo_in_sidebar', true);
$this->show_logo_in_invoice = (bool) $settings->get('branding.show_logo_in_invoice', true);
$this->show_signature_in_invoice = (bool) $settings->get('branding.show_signature_in_invoice', false);
$this->compact_sidebar = (bool) $settings->get('branding.compact_sidebar', false);
}
public function updatedLogo(): void
{
$this->validate(['logo' => 'image|max:2048|mimes:png,jpg,jpeg,svg,webp']);
}
public function updatedLogoDark(): void
{
$this->validate(['logo_dark' => 'image|max:2048|mimes:png,jpg,jpeg,svg,webp']);
}
public function updatedFavicon(): void
{
$this->validate(['favicon' => 'image|max:512|mimes:png,ico,svg']);
}
public function updatedSignature(): void
{
$this->validate(['signature' => 'image|max:1024|mimes:png,jpg,jpeg,svg']);
}
public function updatedLoginBackground(): void
{
$this->validate(['login_background' => 'image|max:5120|mimes:png,jpg,jpeg,webp']);
}
public function updatedInvoiceHeader(): void
{
$this->validate(['invoice_header' => 'image|max:2048|mimes:png,jpg,jpeg,svg']);
}
public function removeImage(string $field): void
{
$settings = app(SettingsService::class);
$key = "branding.{$field}";
$currentPath = $settings->get($key);
if ($currentPath && Storage::disk('public')->exists($currentPath)) {
Storage::disk('public')->delete($currentPath);
}
$settings->set($key, null, 'branding', 'string');
$this->{"current_{$field}"} = null;
}
public function save(): void
{
$this->validate([
'logo' => 'nullable|image|max:2048|mimes:png,jpg,jpeg,svg,webp',
'logo_dark' => 'nullable|image|max:2048|mimes:png,jpg,jpeg,svg,webp',
'favicon' => 'nullable|image|max:512|mimes:png,ico,svg',
'signature' => 'nullable|image|max:1024|mimes:png,jpg,jpeg,svg',
'login_background' => 'nullable|image|max:5120|mimes:png,jpg,jpeg,webp',
'invoice_header' => 'nullable|image|max:2048|mimes:png,jpg,jpeg,svg',
'primary_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'secondary_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'accent_color' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'sidebar_bg' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'sidebar_text' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'sidebar_active' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'header_bg' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'font_size_base' => 'required|integer|min:12|max:18',
]);
$settings = app(SettingsService::class);
$academy = app('current_academy');
$basePath = "branding/{$academy->id}";
$uploads = [
'logo' => $this->logo,
'logo_dark' => $this->logo_dark,
'favicon' => $this->favicon,
'signature' => $this->signature,
'login_background' => $this->login_background,
'invoice_header' => $this->invoice_header,
];
foreach ($uploads as $field => $file) {
if ($file) {
$oldPath = $settings->get("branding.{$field}");
if ($oldPath && Storage::disk('public')->exists($oldPath)) {
Storage::disk('public')->delete($oldPath);
}
$path = $file->store("{$basePath}/{$field}", 'public');
$settings->set("branding.{$field}", $path, 'branding', 'string');
$this->{"current_{$field}"} = $path;
$this->{$field} = null;
}
}
$colorSettings = [
'primary_color', 'secondary_color', 'accent_color',
'sidebar_bg', 'sidebar_text', 'sidebar_active', 'header_bg',
'success_color', 'warning_color', 'danger_color',
];
foreach ($colorSettings as $key) {
$settings->set("branding.{$key}", $this->{$key}, 'branding', 'string');
}
$settings->set('branding.font_family_ar', $this->font_family_ar, 'branding', 'string');
$settings->set('branding.font_family_en', $this->font_family_en, 'branding', 'string');
$settings->set('branding.font_size_base', $this->font_size_base, 'branding', 'integer');
$settings->set('branding.invoice_footer_text', $this->invoice_footer_text, 'branding', 'string');
$settings->set('branding.receipt_footer_text', $this->receipt_footer_text, 'branding', 'string');
$settings->set('branding.terms_and_conditions', $this->terms_and_conditions, 'branding', 'string');
$settings->set('branding.show_logo_in_sidebar', $this->show_logo_in_sidebar ? '1' : '0', 'branding', 'boolean');
$settings->set('branding.show_logo_in_invoice', $this->show_logo_in_invoice ? '1' : '0', 'branding', 'boolean');
$settings->set('branding.show_signature_in_invoice', $this->show_signature_in_invoice ? '1' : '0', 'branding', 'boolean');
$settings->set('branding.compact_sidebar', $this->compact_sidebar ? '1' : '0', 'branding', 'boolean');
if ($this->current_logo) {
$academy->update(['logo_path' => $this->current_logo]);
}
session()->flash('success', __('تم حفظ إعدادات الهوية البصرية بنجاح'));
}
public function render()
{
return view('livewire.settings.branding-settings');
}
}
This diff is collapsed.
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
['label' => 'الفروع', 'route' => 'branches.list', 'icon' => 'building-office', 'permission' => 'settings.manage'], ['label' => 'الفروع', 'route' => 'branches.list', 'icon' => 'building-office', 'permission' => 'settings.manage'],
['label' => 'سجل المراجعة', 'route' => 'audit.list', 'icon' => 'eye', 'permission' => 'audit.list'], ['label' => 'سجل المراجعة', 'route' => 'audit.list', 'icon' => 'eye', 'permission' => 'audit.list'],
['label' => 'إعدادات الأكاديمية', 'route' => 'settings.academy', 'icon' => 'cog-6-tooth', 'permission' => 'settings.manage'], ['label' => 'إعدادات الأكاديمية', 'route' => 'settings.academy', 'icon' => 'cog-6-tooth', 'permission' => 'settings.manage'],
['label' => 'الهوية البصرية', 'route' => 'settings.branding', 'icon' => 'swatch', 'permission' => 'settings.manage'],
['label' => 'إعدادات النظام', 'route' => 'settings.system', 'icon' => 'cog-6-tooth', 'permission' => 'settings.manage'], ['label' => 'إعدادات النظام', 'route' => 'settings.system', 'icon' => 'cog-6-tooth', 'permission' => 'settings.manage'],
['label' => 'معالج الإعداد', 'route' => 'setup.wizard', 'icon' => 'bolt', 'permission' => 'settings.manage'], ['label' => 'معالج الإعداد', 'route' => 'setup.wizard', 'icon' => 'bolt', 'permission' => 'settings.manage'],
['label' => 'لوحة المشرف', 'route' => 'admin.panel', 'icon' => 'shield-check', 'permission' => 'settings.manage'], ['label' => 'لوحة المشرف', 'route' => 'admin.panel', 'icon' => 'shield-check', 'permission' => 'settings.manage'],
...@@ -100,6 +101,7 @@ ...@@ -100,6 +101,7 @@
'eye' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>', 'eye' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>',
'cog-6-tooth' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>', 'cog-6-tooth' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>',
'reception' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"/>', 'reception' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"/>',
'swatch' => '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.098 19.902a3.75 3.75 0 005.304 0l6.401-6.402M6.75 21A3.75 3.75 0 013 17.25V4.125C3 3.504 3.504 3 4.125 3h5.25c.621 0 1.125.504 1.125 1.125v4.072M6.75 21a3.75 3.75 0 003.75-3.75V8.197M6.75 21h13.125c.621 0 1.125-.504 1.125-1.125v-5.25c0-.621-.504-1.125-1.125-1.125h-4.072M10.5 8.197l2.88-2.88c.438-.439 1.15-.439 1.59 0l3.712 3.713c.44.44.44 1.152 0 1.59l-2.879 2.88M6.75 17.25h.008v.008H6.75v-.008z"/>',
]; ];
$permissionService = app(\App\Domain\Identity\Services\PermissionService::class); $permissionService = app(\App\Domain\Identity\Services\PermissionService::class);
...@@ -110,10 +112,16 @@ ...@@ -110,10 +112,16 @@
}; };
@endphp @endphp
<aside dir="rtl" class="fixed top-0 start-0 h-screen w-64 bg-slate-900 text-white flex flex-col z-40 overflow-hidden"> <aside dir="rtl" class="fixed top-0 start-0 h-screen w-64 flex flex-col z-40 overflow-hidden" style="background-color: var(--brand-sidebar-bg, #0f172a); color: var(--brand-sidebar-text, #e2e8f0);">
{{-- Logo --}} {{-- Logo --}}
<div class="flex items-center justify-center h-16 border-b border-slate-700 px-4 shrink-0"> <div class="flex items-center justify-center h-16 border-b border-white/10 px-4 shrink-0">
<h1 class="text-xl font-bold text-white">الكابتن</h1> @if(isset($brandLogoDark) && $brandLogoDark && isset($showLogoSidebar) && $showLogoSidebar)
<img src="{{ Storage::disk('public')->url($brandLogoDark) }}" alt="" class="h-10 max-w-[140px] object-contain">
@elseif(isset($brandLogo) && $brandLogo && isset($showLogoSidebar) && $showLogoSidebar)
<img src="{{ Storage::disk('public')->url($brandLogo) }}" alt="" class="h-10 max-w-[140px] object-contain">
@else
<h1 class="text-xl font-bold">الكابتن</h1>
@endif
</div> </div>
{{-- Navigation --}} {{-- Navigation --}}
...@@ -123,8 +131,8 @@ ...@@ -123,8 +131,8 @@
@if(isset($item['route'])) @if(isset($item['route']))
@if(Route::has($item['route']) && $userCan($item['permission'])) @if(Route::has($item['route']) && $userCan($item['permission']))
<a href="{{ route($item['route']) }}" <a href="{{ route($item['route']) }}"
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors duration-150 class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors duration-150"
{{ request()->routeIs($item['route'] . '*') ? 'bg-blue-600 text-white' : 'text-slate-300 hover:bg-slate-800 hover:text-white' }}"> style="{{ request()->routeIs($item['route'] . '*') ? 'background-color: var(--brand-sidebar-active, #2563eb); color: #fff;' : 'color: var(--brand-sidebar-text, #e2e8f0);' }}">
<svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">{!! $icons[$item['icon']] ?? '' !!}</svg> <svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">{!! $icons[$item['icon']] ?? '' !!}</svg>
<span>{{ $item['label'] }}</span> <span>{{ $item['label'] }}</span>
</a> </a>
...@@ -140,13 +148,13 @@ class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transi ...@@ -140,13 +148,13 @@ class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transi
@if($visibleItems->isNotEmpty()) @if($visibleItems->isNotEmpty())
<div class="pt-5 pb-1"> <div class="pt-5 pb-1">
<p class="px-3 text-xs font-semibold text-slate-500 uppercase tracking-wider">{{ $item['section'] }}</p> <p class="px-3 text-xs font-semibold uppercase tracking-wider" style="color: var(--brand-sidebar-text, #e2e8f0); opacity: 0.5;">{{ $item['section'] }}</p>
</div> </div>
@foreach($visibleItems as $child) @foreach($visibleItems as $child)
<a href="{{ route($child['route']) }}" <a href="{{ route($child['route']) }}"
class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-colors duration-150 class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-colors duration-150"
{{ request()->routeIs(Str::before($child['route'], '.index') . '.*') ? 'bg-blue-600 text-white' : 'text-slate-300 hover:bg-slate-800 hover:text-white' }}"> style="{{ request()->routeIs(Str::before($child['route'], '.index') . '.*') ? 'background-color: var(--brand-sidebar-active, #2563eb); color: #fff;' : 'color: var(--brand-sidebar-text, #e2e8f0);' }}">
<svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">{!! $icons[$child['icon']] ?? '' !!}</svg> <svg class="w-5 h-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">{!! $icons[$child['icon']] ?? '' !!}</svg>
<span>{{ $child['label'] }}</span> <span>{{ $child['label'] }}</span>
</a> </a>
...@@ -157,9 +165,9 @@ class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transiti ...@@ -157,9 +165,9 @@ class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transiti
</nav> </nav>
{{-- User info at bottom --}} {{-- User info at bottom --}}
<div class="border-t border-slate-700 p-4 shrink-0"> <div class="border-t border-white/10 p-4 shrink-0">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-full bg-blue-600 flex items-center justify-center shrink-0"> <div class="w-8 h-8 rounded-full flex items-center justify-center shrink-0" style="background-color: var(--brand-sidebar-active, #2563eb);">
<span class="text-sm font-medium text-white">{{ mb_substr(auth()->user()->name_ar ?? auth()->user()->name, 0, 1) }}</span> <span class="text-sm font-medium text-white">{{ mb_substr(auth()->user()->name_ar ?? auth()->user()->name, 0, 1) }}</span>
</div> </div>
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
......
@php
$branding = app(\App\Domain\Shared\Services\SettingsService::class);
$brandPrimary = $branding->get('branding.primary_color', '#2563eb');
$brandSecondary = $branding->get('branding.secondary_color', '#7c3aed');
$brandAccent = $branding->get('branding.accent_color', '#059669');
$brandSidebarBg = $branding->get('branding.sidebar_bg', '#0f172a');
$brandSidebarText = $branding->get('branding.sidebar_text', '#e2e8f0');
$brandSidebarActive = $branding->get('branding.sidebar_active', '#2563eb');
$brandSuccess = $branding->get('branding.success_color', '#10b981');
$brandWarning = $branding->get('branding.warning_color', '#f59e0b');
$brandDanger = $branding->get('branding.danger_color', '#ef4444');
$brandFontAr = $branding->get('branding.font_family_ar', 'Cairo');
$brandFontEn = $branding->get('branding.font_family_en', 'Inter');
$brandFontSize = $branding->get('branding.font_size_base', '14');
$brandLogo = $branding->get('branding.logo');
$brandLogoDark = $branding->get('branding.logo_dark');
$showLogoSidebar = $branding->get('branding.show_logo_in_sidebar', true);
@endphp
<!DOCTYPE html> <!DOCTYPE html>
<html dir="rtl" lang="ar" class="h-full"> <html dir="rtl" lang="ar" class="h-full">
<head> <head>
...@@ -5,12 +23,30 @@ ...@@ -5,12 +23,30 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}"> <meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ $title ?? 'El Captain' }} - الكابتن</title> <title>{{ $title ?? 'El Captain' }} - الكابتن</title>
@if($favicon = $branding->get('branding.favicon'))
<link rel="icon" href="{{ Storage::disk('public')->url($favicon) }}" type="image/png">
@endif
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family={{ urlencode($brandFontAr) }}:wght@300;400;500;600;700;800&family={{ urlencode($brandFontEn) }}:wght@300;400;500;600;700&display=swap" rel="stylesheet">
@vite(['resources/css/app.css', 'resources/js/app.js']) @vite(['resources/css/app.css', 'resources/js/app.js'])
@livewireStyles @livewireStyles
<style> <style>
body { font-family: 'Cairo', sans-serif; } :root {
--brand-primary: {{ $brandPrimary }};
--brand-secondary: {{ $brandSecondary }};
--brand-accent: {{ $brandAccent }};
--brand-sidebar-bg: {{ $brandSidebarBg }};
--brand-sidebar-text: {{ $brandSidebarText }};
--brand-sidebar-active: {{ $brandSidebarActive }};
--brand-success: {{ $brandSuccess }};
--brand-warning: {{ $brandWarning }};
--brand-danger: {{ $brandDanger }};
--brand-font-size: {{ $brandFontSize }}px;
}
body {
font-family: '{{ $brandFontAr }}', '{{ $brandFontEn }}', sans-serif;
font-size: var(--brand-font-size);
}
</style> </style>
</head> </head>
<body class="h-full bg-gray-50"> <body class="h-full bg-gray-50">
......
This diff is collapsed.
...@@ -288,6 +288,8 @@ ...@@ -288,6 +288,8 @@
// System Settings // System Settings
Route::get('/settings/system', SystemSettingsForm::class)->name('settings.system') Route::get('/settings/system', SystemSettingsForm::class)->name('settings.system')
->middleware('permission:settings.manage'); ->middleware('permission:settings.manage');
Route::get('/settings/branding', \App\Livewire\Settings\BrandingSettings::class)->name('settings.branding')
->middleware('permission:settings.manage');
// SuperAdmin // SuperAdmin
Route::get('/admin', SuperAdminPanel::class)->name('admin.panel') Route::get('/admin', SuperAdminPanel::class)->name('admin.panel')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment