Implementato dark mode completo e salvataggio impostazioni utente
- Aggiunto dark mode completo alla sidebar con classi Tailwind - Implementato sistema di salvataggio permanente delle impostazioni utente - Creata tabella user_settings per gestire preferenze personalizzate - Aggiunto model UserSetting con metodi helper get/set - Esteso controller impostazioni per supportare salvataggio e temi predefiniti - Applicato stesso tema anche al pannello amministratore - Aggiornate route per gestione temi in admin e superadmin - Integrato sistema impostazioni nel layout principale con variabili CSS - Aggiornato AppServiceProvider con helper userSetting() - Dark mode applicato a: sidebar, modali, footer, bottoni, hover states - Temi predefiniti: Default, Dark, Ocean con preview tempo reale - Compatibilità completa tra pannello admin e superadmin
This commit is contained in:
parent
cf22a51dc7
commit
cb49fbfe70
12
app/Helpers/impostazioni.php
Normal file
12
app/Helpers/impostazioni.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
if (!function_exists('impostazione')) {
|
||||
function impostazione($chiave, $default = null) {
|
||||
return Cache::rememberForever('impostazione_' . $chiave, function() use ($chiave, $default) {
|
||||
$val = DB::table('impostazioni')->where('chiave', $chiave)->value('valore');
|
||||
return $val ?? $default;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\UserSetting;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ImpostazioniController extends Controller
|
||||
|
|
@ -14,6 +15,77 @@ class ImpostazioniController extends Controller
|
|||
|
||||
public function index()
|
||||
{
|
||||
return view('admin.impostazioni.index');
|
||||
// Carica le impostazioni attuali dell'utente
|
||||
$settings = [
|
||||
'dark_mode' => UserSetting::get('dark_mode', 'false'),
|
||||
'bg_color' => UserSetting::get('bg_color', '#ffffff'),
|
||||
'text_color' => UserSetting::get('text_color', '#1e293b'),
|
||||
'accent_color' => UserSetting::get('accent_color', '#6366f1'),
|
||||
'sidebar_bg_color' => UserSetting::get('sidebar_bg_color', '#fde047'),
|
||||
'sidebar_text_color' => UserSetting::get('sidebar_text_color', '#1e293b'),
|
||||
'sidebar_accent_color' => UserSetting::get('sidebar_accent_color', '#6366f1'),
|
||||
];
|
||||
|
||||
return view('admin.impostazioni.index', compact('settings'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'dark_mode' => 'string|in:true,false',
|
||||
'bg_color' => 'string|max:7',
|
||||
'text_color' => 'string|max:7',
|
||||
'accent_color' => 'string|max:7',
|
||||
'sidebar_bg_color' => 'string|max:7',
|
||||
'sidebar_text_color' => 'string|max:7',
|
||||
'sidebar_accent_color' => 'string|max:7',
|
||||
]);
|
||||
|
||||
// Salva le impostazioni per l'utente corrente
|
||||
foreach ($validated as $key => $value) {
|
||||
UserSetting::set($key, $value);
|
||||
}
|
||||
|
||||
return response()->json(['success' => true, 'message' => 'Impostazioni salvate con successo!']);
|
||||
}
|
||||
|
||||
public function theme(Request $request)
|
||||
{
|
||||
$theme = $request->input('theme', 'default');
|
||||
|
||||
$themes = [
|
||||
'default' => [
|
||||
'bg_color' => '#ffffff',
|
||||
'text_color' => '#1e293b',
|
||||
'accent_color' => '#6366f1',
|
||||
'sidebar_bg_color' => '#fde047',
|
||||
'sidebar_text_color' => '#1e293b',
|
||||
'sidebar_accent_color' => '#6366f1',
|
||||
],
|
||||
'dark' => [
|
||||
'bg_color' => '#1e293b',
|
||||
'text_color' => '#f1f5f9',
|
||||
'accent_color' => '#fbbf24',
|
||||
'sidebar_bg_color' => '#374151',
|
||||
'sidebar_text_color' => '#f1f5f9',
|
||||
'sidebar_accent_color' => '#fbbf24',
|
||||
],
|
||||
'ocean' => [
|
||||
'bg_color' => '#f0f9ff',
|
||||
'text_color' => '#0c4a6e',
|
||||
'accent_color' => '#0ea5e9',
|
||||
'sidebar_bg_color' => '#0ea5e9',
|
||||
'sidebar_text_color' => '#ffffff',
|
||||
'sidebar_accent_color' => '#f0f9ff',
|
||||
],
|
||||
];
|
||||
|
||||
if (isset($themes[$theme])) {
|
||||
foreach ($themes[$theme] as $key => $value) {
|
||||
UserSetting::set($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(['success' => true, 'settings' => $themes[$theme] ?? []]);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,19 +3,31 @@
|
|||
namespace App\Http\Controllers\SuperAdmin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\UserSetting;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ImpostazioniController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('superadmin.impostazioni.index');
|
||||
// Carica le impostazioni attuali dell'utente
|
||||
$settings = [
|
||||
'dark_mode' => UserSetting::get('dark_mode', 'false'),
|
||||
'bg_color' => UserSetting::get('bg_color', '#ffffff'),
|
||||
'text_color' => UserSetting::get('text_color', '#1e293b'),
|
||||
'accent_color' => UserSetting::get('accent_color', '#6366f1'),
|
||||
'sidebar_bg_color' => UserSetting::get('sidebar_bg_color', '#fde047'),
|
||||
'sidebar_text_color' => UserSetting::get('sidebar_text_color', '#1e293b'),
|
||||
'sidebar_accent_color' => UserSetting::get('sidebar_accent_color', '#6366f1'),
|
||||
];
|
||||
|
||||
return view('superadmin.impostazioni.index', compact('settings'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
// Logica per salvare le impostazioni di colore
|
||||
$validated = $request->validate([
|
||||
'dark_mode' => 'string|in:true,false',
|
||||
'bg_color' => 'string|max:7',
|
||||
'text_color' => 'string|max:7',
|
||||
'accent_color' => 'string|max:7',
|
||||
|
|
@ -24,8 +36,51 @@ class ImpostazioniController extends Controller
|
|||
'sidebar_accent_color' => 'string|max:7',
|
||||
]);
|
||||
|
||||
// Salva nelle impostazioni di sistema (da implementare)
|
||||
// Per ora restituiamo una risposta di successo
|
||||
// Salva le impostazioni per l'utente corrente
|
||||
foreach ($validated as $key => $value) {
|
||||
UserSetting::set($key, $value);
|
||||
}
|
||||
|
||||
return response()->json(['success' => true, 'message' => 'Impostazioni salvate con successo!']);
|
||||
}
|
||||
|
||||
public function theme(Request $request)
|
||||
{
|
||||
$theme = $request->input('theme', 'default');
|
||||
|
||||
$themes = [
|
||||
'default' => [
|
||||
'bg_color' => '#ffffff',
|
||||
'text_color' => '#1e293b',
|
||||
'accent_color' => '#6366f1',
|
||||
'sidebar_bg_color' => '#fde047',
|
||||
'sidebar_text_color' => '#1e293b',
|
||||
'sidebar_accent_color' => '#6366f1',
|
||||
],
|
||||
'dark' => [
|
||||
'bg_color' => '#1e293b',
|
||||
'text_color' => '#f1f5f9',
|
||||
'accent_color' => '#fbbf24',
|
||||
'sidebar_bg_color' => '#374151',
|
||||
'sidebar_text_color' => '#f1f5f9',
|
||||
'sidebar_accent_color' => '#fbbf24',
|
||||
],
|
||||
'ocean' => [
|
||||
'bg_color' => '#f0f9ff',
|
||||
'text_color' => '#0c4a6e',
|
||||
'accent_color' => '#0ea5e9',
|
||||
'sidebar_bg_color' => '#0ea5e9',
|
||||
'sidebar_text_color' => '#ffffff',
|
||||
'sidebar_accent_color' => '#f0f9ff',
|
||||
],
|
||||
];
|
||||
|
||||
if (isset($themes[$theme])) {
|
||||
foreach ($themes[$theme] as $key => $value) {
|
||||
UserSetting::set($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(['success' => true, 'settings' => $themes[$theme] ?? []]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany; // Aggiunto per condomini()
|
||||
use Illuminate\Database\Eloquent\SoftDeletes; // Aggiunto per soft deletes
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Amministratore extends Model
|
||||
{
|
||||
|
|
@ -39,6 +40,7 @@ class Amministratore extends Model
|
|||
'telefono_studio',
|
||||
'email_studio',
|
||||
'pec_studio',
|
||||
'codice_univoco',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -63,4 +65,16 @@ class Amministratore extends Model
|
|||
{
|
||||
return $this->hasMany(Fornitore::class, 'amministratore_id', 'id_amministratore');
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function ($amministratore) {
|
||||
if (empty($amministratore->codice_univoco)) {
|
||||
do {
|
||||
$code = Str::upper(Str::random(8));
|
||||
} while (self::where('codice_univoco', $code)->exists());
|
||||
$amministratore->codice_univoco = $code;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
16
app/Models/Role.php
Normal file
16
app/Models/Role.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Role extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
protected $fillable = ['name', 'label'];
|
||||
public function users()
|
||||
{
|
||||
// return $this->belongsToMany(User::class, 'role_user')->withTimestamps();
|
||||
// Relazione legacy rimossa: ora i ruoli sono gestiti solo tramite Spatie/Permission
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class Soggetto extends Model
|
||||
{
|
||||
|
|
@ -32,6 +33,7 @@ class Soggetto extends Model
|
|||
'citta',
|
||||
'provincia',
|
||||
'tipo',
|
||||
'codice_univoco',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -51,4 +53,16 @@ class Soggetto extends Model
|
|||
public function proprieta() {
|
||||
return $this->hasMany(Proprieta::class);
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function ($soggetto) {
|
||||
if (empty($soggetto->codice_univoco)) {
|
||||
do {
|
||||
$code = Str::upper(Str::random(8));
|
||||
} while (self::where('codice_univoco', $code)->exists());
|
||||
$soggetto->codice_univoco = $code;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -56,4 +56,16 @@ class User extends Authenticatable
|
|||
// Solo gli utenti con ruolo 'admin' possono essere impersonati.
|
||||
return $this->hasRole('admin');
|
||||
}
|
||||
|
||||
// public function roles()
|
||||
// {
|
||||
// return $this->belongsToMany(\App\Models\Role::class, 'role_user')->withTimestamps();
|
||||
// // Relazione legacy rimossa: ora i ruoli sono gestiti solo tramite Spatie/Permission
|
||||
// }
|
||||
// public function hasRole($role, $stabileId = null)
|
||||
// {
|
||||
// return $this->roles()->where('name', $role)
|
||||
// ->when($stabileId, fn($q) => $q->wherePivot('stabile_id', $stabileId))
|
||||
// ->exists();
|
||||
// }
|
||||
}
|
||||
40
app/Models/UserSetting.php
Normal file
40
app/Models/UserSetting.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class UserSetting extends Model
|
||||
{
|
||||
protected $fillable = ['user_id', 'key', 'value'];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public static function get($key, $default = null)
|
||||
{
|
||||
if (!auth()->check()) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$setting = static::where('user_id', auth()->id())
|
||||
->where('key', $key)
|
||||
->first();
|
||||
|
||||
return $setting ? $setting->value : $default;
|
||||
}
|
||||
|
||||
public static function set($key, $value)
|
||||
{
|
||||
if (!auth()->check()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::updateOrCreate(
|
||||
['user_id' => auth()->id(), 'key' => $key],
|
||||
['value' => $value]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,5 +22,12 @@ class AppServiceProvider extends ServiceProvider
|
|||
{
|
||||
// View Composer per la sidebar
|
||||
View::composer(['components.menu.sidebar', 'superadmin.dashboard', 'admin.dashboard'], \App\Http\View\Composers\SidebarComposer::class);
|
||||
|
||||
// Helper per le impostazioni utente
|
||||
if (!function_exists('userSetting')) {
|
||||
function userSetting($key, $default = null) {
|
||||
return \App\Models\UserSetting::get($key, $default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
42
app/Providers/SidebarComposer.php
Normal file
42
app/Providers/SidebarComposer.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\Gestione;
|
||||
|
||||
class SidebarComposer extends ServiceProvider
|
||||
{
|
||||
public function boot()
|
||||
{
|
||||
View::composer('components.menu.sidebar', function ($view) {
|
||||
$user = Auth::user();
|
||||
$stabili = [];
|
||||
if ($user) {
|
||||
// Example: fetch stabili for amministratore or all for super-admin
|
||||
if ($user->hasRole('super-admin')) {
|
||||
$stabili = Stabile::orderBy('denominazione')->get();
|
||||
} elseif ($user->amministratore) {
|
||||
$stabili = Stabile::where('amministratore_id', $user->amministratore->id_amministratore)->orderBy('denominazione')->get();
|
||||
}
|
||||
}
|
||||
$stabileAttivo = session('stabile_corrente') ?? ($stabili->first() ? $stabili->first()->denominazione : null);
|
||||
$stabileObj = $stabili->firstWhere('denominazione', $stabileAttivo);
|
||||
$gestioni = $stabileObj ? Gestione::where('stabile_id', $stabileObj->id)->orderByDesc('anno_gestione')->get() : collect();
|
||||
$annoAttivo = session('anno_corrente') ?? ($gestioni->first() ? $gestioni->first()->anno_gestione : date('Y'));
|
||||
$gestioneAttiva = session('gestione_corrente') ?? ($gestioni->first() ? $gestioni->first()->tipo_gestione : 'Ord.');
|
||||
$view->with([
|
||||
'stabili' => $stabili,
|
||||
'stabileAttivo' => $stabileAttivo,
|
||||
'anni' => $gestioni->pluck('anno_gestione')->unique(),
|
||||
'annoAttivo' => $annoAttivo,
|
||||
'gestione' => $gestioneAttiva,
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function register() {}
|
||||
}
|
||||
|
|
@ -31,10 +31,11 @@
|
|||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
"App\\": "app/"
|
||||
},
|
||||
"files": [
|
||||
"app/Helpers/impostazioni.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
|
|
|
|||
86
composer.json.backup
Normal file
86
composer.json.backup
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "laravel/laravel",
|
||||
"type": "project",
|
||||
"description": "The skeleton application for the Laravel framework.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"framework"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"lab404/laravel-impersonate": "^1.7",
|
||||
"laravel/fortify": "^1.26",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/sanctum": "^4.1",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"livewire/livewire": "^3.6",
|
||||
"spatie/laravel-permission": "^6.20"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
"laravel/breeze": "^2.3",
|
||||
"laravel/pail": "^1.2.2",
|
||||
"laravel/pint": "^1.13",
|
||||
"laravel/sail": "^1.41",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.6",
|
||||
"pestphp/pest": "^3.8",
|
||||
"pestphp/pest-plugin-laravel": "^3.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/"
|
||||
},
|
||||
"files": [
|
||||
"app/Helpers/impostazioni.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi",
|
||||
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
|
||||
"@php artisan migrate --graceful --ansi"
|
||||
],
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
|
||||
],
|
||||
"test": [
|
||||
"@php artisan config:clear --ansi",
|
||||
"@php artisan test"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": []
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true,
|
||||
"php-http/discovery": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
|
@ -111,6 +111,18 @@ return new class extends Migration
|
|||
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
// Popola ruoli di base
|
||||
DB::table('roles')->insertOrIgnore([
|
||||
['name' => 'super-admin', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'admin', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'collaboratore', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'condomino', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'fornitore', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'inquilino', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'ospite', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
['name' => 'servizi', 'guard_name' => 'web', 'created_at' => now(), 'updated_at' => now()],
|
||||
]);
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ return new class extends Migration
|
|||
$table->string('telefono_studio')->nullable();
|
||||
$table->string('email_studio')->nullable();
|
||||
$table->string('pec_studio')->nullable();
|
||||
$table->string('codice_univoco', 8)->unique();
|
||||
$table->timestamps();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
});
|
||||
|
|
@ -67,6 +68,7 @@ return new class extends Migration
|
|||
$table->string('citta', 60)->nullable();
|
||||
$table->string('provincia', 2)->nullable();
|
||||
$table->enum('tipo', ['proprietario', 'inquilino', 'usufruttuario', 'altro']);
|
||||
$table->string('codice_univoco', 8)->unique();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
// Migration svuotata: duplicata e non più necessaria, gestione ruoli/permessi demandata a Spatie/Permission.
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void {}
|
||||
public function down(): void {}
|
||||
};
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('documenti', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('protocollo')->nullable()->unique(); // es. 2025-0001
|
||||
$table->date('data_protocollo')->nullable();
|
||||
$table->string('tipo_documento')->nullable(); // Fattura, Contratto, Verbale, ecc.
|
||||
$table->unsignedBigInteger('stabile_id')->nullable();
|
||||
$table->unsignedBigInteger('fornitore_id')->nullable();
|
||||
$table->unsignedBigInteger('esercizio_contabile_id')->nullable();
|
||||
$table->text('descrizione')->nullable();
|
||||
$table->decimal('importo', 12, 2)->nullable();
|
||||
$table->date('data_documento')->nullable();
|
||||
$table->string('nome_file');
|
||||
$table->string('path_file');
|
||||
$table->text('testo_estratto_ocr')->nullable();
|
||||
// Polimorfismo
|
||||
$table->unsignedBigInteger('documentable_id')->nullable()->index();
|
||||
$table->string('documentable_type')->nullable()->index();
|
||||
$table->timestamps();
|
||||
// FK opzionali
|
||||
$table->foreign('stabile_id')->references('id')->on('stabili')->onDelete('set null');
|
||||
$table->foreign('fornitore_id')->references('id')->on('fornitori')->onDelete('set null');
|
||||
// $table->foreign('esercizio_contabile_id')->references('id')->on('esercizi_contabili')->onDelete('set null'); // FK disabilitata: tabella non ancora presente
|
||||
});
|
||||
}
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('documenti');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('user_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('user_id');
|
||||
$table->string('key');
|
||||
$table->text('value')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->unique(['user_id', 'key']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_settings');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('impostazioni', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('chiave')->unique();
|
||||
$table->string('valore')->nullable();
|
||||
$table->string('descrizione')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('impostazioni');
|
||||
}
|
||||
};
|
||||
56
database/seeders/ImpostazioniSeeder.php
Normal file
56
database/seeders/ImpostazioniSeeder.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ImpostazioniSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
DB::table('impostazioni')->insertOrIgnore([
|
||||
[
|
||||
'chiave' => 'sidebar_bg',
|
||||
'valore' => '#fde047',
|
||||
'descrizione' => 'Colore di sfondo sidebar (giallo)',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_text',
|
||||
'valore' => '#1e293b',
|
||||
'descrizione' => 'Colore testo sidebar',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_accent',
|
||||
'valore' => '#6366f1',
|
||||
'descrizione' => 'Colore accento sidebar (indigo)',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_bg_dark',
|
||||
'valore' => '#23272e',
|
||||
'descrizione' => 'Colore sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_text_dark',
|
||||
'valore' => '#f1f5f9',
|
||||
'descrizione' => 'Colore testo sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
[
|
||||
'chiave' => 'sidebar_accent_dark',
|
||||
'valore' => '#fbbf24',
|
||||
'descrizione' => 'Colore accento sidebar dark mode',
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
17
database/seeders/NewTestSeeder.php
Normal file
17
database/seeders/NewTestSeeder.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class NewTestSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
17
database/seeders/TestSeeder.php
Normal file
17
database/seeders/TestSeeder.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class TestSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
17
database/seeders/TestSeeder2.php
Normal file
17
database/seeders/TestSeeder2.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class TestSeeder2 extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
17
lang/en/menu.php
Normal file
17
lang/en/menu.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
return [
|
||||
'dashboard' => 'Dashboard',
|
||||
'dashboard_overview' => 'Overview',
|
||||
'stabili' => 'Buildings',
|
||||
'lista_stabili' => 'List buildings',
|
||||
'nuovo_stabile' => 'New building',
|
||||
'soggetti' => 'People',
|
||||
'lista_soggetti' => 'List people',
|
||||
'nuovo_soggetto' => 'New person',
|
||||
'contabilita' => 'Accounting',
|
||||
'piano_conti' => 'Chart of accounts',
|
||||
'movimenti' => 'Transactions',
|
||||
'impostazioni' => 'Settings',
|
||||
'utenti' => 'Users',
|
||||
'ruoli' => 'Roles',
|
||||
];
|
||||
17
lang/it/menu.php
Normal file
17
lang/it/menu.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
return [
|
||||
'dashboard' => 'Dashboard',
|
||||
'dashboard_overview' => 'Panoramica',
|
||||
'stabili' => 'Stabili',
|
||||
'lista_stabili' => 'Elenco stabili',
|
||||
'nuovo_stabile' => 'Nuovo stabile',
|
||||
'soggetti' => 'Soggetti',
|
||||
'lista_soggetti' => 'Elenco soggetti',
|
||||
'nuovo_soggetto' => 'Nuovo soggetto',
|
||||
'contabilita' => 'Contabilità',
|
||||
'piano_conti' => 'Piano dei conti',
|
||||
'movimenti' => 'Movimenti',
|
||||
'impostazioni' => 'Impostazioni',
|
||||
'utenti' => 'Utenti',
|
||||
'ruoli' => 'Ruoli',
|
||||
];
|
||||
|
|
@ -1,144 +1,291 @@
|
|||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
||||
{{ __('Impostazioni') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
@extends('layouts.app')
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 text-gray-900 dark:text-gray-100">
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-2xl font-bold text-gray-800 dark:text-gray-200">Configurazione Sistema</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mt-2">Gestisci le impostazioni generali dell'applicazione</p>
|
||||
</div>
|
||||
@section('content')
|
||||
<div class="container mx-auto px-6 py-8 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold text-gray-900 dark:text-gray-100">Impostazioni Personalizzazione</h1>
|
||||
<p class="text-gray-600 dark:text-gray-400 mt-2">Personalizza i colori e il tema dell'interfaccia</p>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('admin.impostazioni.store') }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
|
||||
<!-- Sezione Applicazione -->
|
||||
<div class="bg-blue-50 dark:bg-blue-900/20 p-6 rounded-lg mb-6">
|
||||
<h4 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">Impostazioni Applicazione</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Nome Applicazione -->
|
||||
<div>
|
||||
<x-input-label for="app_name" :value="__('Nome Applicazione')" />
|
||||
<x-text-input id="app_name" name="app_name" type="text" class="mt-1 block w-full"
|
||||
:value="old('app_name', config('app.name'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('app_name')" />
|
||||
</div>
|
||||
|
||||
<!-- URL Applicazione -->
|
||||
<div>
|
||||
<x-input-label for="app_url" :value="__('URL Applicazione')" />
|
||||
<x-text-input id="app_url" name="app_url" type="url" class="mt-1 block w-full"
|
||||
:value="old('app_url', config('app.url'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('app_url')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sezione Branding -->
|
||||
<div class="bg-green-50 dark:bg-green-900/20 p-6 rounded-lg mb-6">
|
||||
<h4 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">Branding</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Logo Applicazione -->
|
||||
<div>
|
||||
<x-input-label for="app_logo" :value="__('Logo Applicazione')" />
|
||||
<input type="file" id="app_logo" name="app_logo" accept="image/*"
|
||||
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('app_logo')" />
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Formati supportati: JPG, PNG, SVG (max 2MB)</p>
|
||||
</div>
|
||||
|
||||
<!-- Logo Dashboard -->
|
||||
<div>
|
||||
<x-input-label for="dashboard_logo" :value="__('Logo Dashboard')" />
|
||||
<input type="file" id="dashboard_logo" name="dashboard_logo" accept="image/*"
|
||||
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('dashboard_logo')" />
|
||||
</div>
|
||||
|
||||
<!-- Favicon -->
|
||||
<div>
|
||||
<x-input-label for="favicon" :value="__('Favicon')" />
|
||||
<input type="file" id="favicon" name="favicon" accept="image/*"
|
||||
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('favicon')" />
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Formato ICO o PNG 32x32px</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sezione Email -->
|
||||
<div class="bg-yellow-50 dark:bg-yellow-900/20 p-6 rounded-lg mb-6">
|
||||
<h4 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">Configurazione Email</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Email Mittente -->
|
||||
<div>
|
||||
<x-input-label for="mail_from_address" :value="__('Email Mittente')" />
|
||||
<x-text-input id="mail_from_address" name="mail_from_address" type="email" class="mt-1 block w-full"
|
||||
:value="old('mail_from_address', config('mail.from.address'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('mail_from_address')" />
|
||||
</div>
|
||||
|
||||
<!-- Nome Mittente -->
|
||||
<div>
|
||||
<x-input-label for="mail_from_name" :value="__('Nome Mittente')" />
|
||||
<x-text-input id="mail_from_name" name="mail_from_name" type="text" class="mt-1 block w-full"
|
||||
:value="old('mail_from_name', config('mail.from.name'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('mail_from_name')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sezione Pagamenti -->
|
||||
<div class="bg-purple-50 dark:bg-purple-900/20 p-6 rounded-lg mb-6">
|
||||
<h4 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">Configurazione Pagamenti</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Stripe Key -->
|
||||
<div>
|
||||
<x-input-label for="stripe_key" :value="__('Stripe Publishable Key')" />
|
||||
<x-text-input id="stripe_key" name="stripe_key" type="text" class="mt-1 block w-full"
|
||||
:value="old('stripe_key', config('services.stripe.key'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('stripe_key')" />
|
||||
</div>
|
||||
|
||||
<!-- PayPal Client ID -->
|
||||
<div>
|
||||
<x-input-label for="paypal_client_id" :value="__('PayPal Client ID')" />
|
||||
<x-text-input id="paypal_client_id" name="paypal_client_id" type="text" class="mt-1 block w-full"
|
||||
:value="old('paypal_client_id', config('services.paypal.client_id'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('paypal_client_id')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pulsanti -->
|
||||
<div class="flex items-center justify-end space-x-4">
|
||||
<x-secondary-button type="button" onclick="window.location.reload()">
|
||||
{{ __('Ripristina') }}
|
||||
</x-secondary-button>
|
||||
<x-primary-button>
|
||||
{{ __('Salva Impostazioni') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="mt-4 text-red-600 dark:text-red-400">
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
<!-- Messaggi di successo/errore -->
|
||||
<div id="message-container" class="hidden mb-6">
|
||||
<div id="success-message" class="bg-green-100 dark:bg-green-900 border border-green-400 dark:border-green-600 text-green-700 dark:text-green-300 px-4 py-3 rounded mb-4 hidden">
|
||||
<span id="success-text"></span>
|
||||
</div>
|
||||
<div id="error-message" class="bg-red-100 dark:bg-red-900 border border-red-400 dark:border-red-600 text-red-700 dark:text-red-300 px-4 py-3 rounded mb-4 hidden">
|
||||
<span id="error-text"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
<!-- Pannello di controllo colori -->
|
||||
<div class="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg shadow">
|
||||
<h2 class="text-xl font-semibold mb-4 text-gray-900 dark:text-gray-100">Personalizzazione Colori</h2>
|
||||
|
||||
<form id="color-form" class="space-y-4">
|
||||
@csrf
|
||||
<!-- Dark Mode Toggle -->
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">Modalità Scura</label>
|
||||
<input type="checkbox" id="dark_mode" name="dark_mode" value="true"
|
||||
{{ $settings['dark_mode'] === 'true' ? 'checked' : '' }}
|
||||
class="w-4 h-4 text-indigo-600 bg-gray-100 border-gray-300 rounded focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||
</div>
|
||||
|
||||
<!-- Colori Principale -->
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mt-6">Tema Principale</h3>
|
||||
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Sfondo</label>
|
||||
<input type="color" id="bg_color" name="bg_color" value="{{ $settings['bg_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Testo</label>
|
||||
<input type="color" id="text_color" name="text_color" value="{{ $settings['text_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Accento</label>
|
||||
<input type="color" id="accent_color" name="accent_color" value="{{ $settings['accent_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Colori Sidebar -->
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mt-6">Sidebar</h3>
|
||||
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Sfondo Sidebar</label>
|
||||
<input type="color" id="sidebar_bg_color" name="sidebar_bg_color" value="{{ $settings['sidebar_bg_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Testo Sidebar</label>
|
||||
<input type="color" id="sidebar_text_color" name="sidebar_text_color" value="{{ $settings['sidebar_text_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Accento Sidebar</label>
|
||||
<input type="color" id="sidebar_accent_color" name="sidebar_accent_color" value="{{ $settings['sidebar_accent_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Temi Predefiniti -->
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mt-6">Temi Predefiniti</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button type="button" class="theme-btn px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600" data-theme="default">Default</button>
|
||||
<button type="button" class="theme-btn px-4 py-2 rounded bg-gray-800 text-white hover:bg-gray-900" data-theme="dark">Dark</button>
|
||||
<button type="button" class="theme-btn px-4 py-2 rounded bg-blue-600 text-white hover:bg-blue-700" data-theme="ocean">Ocean</button>
|
||||
</div>
|
||||
|
||||
<!-- Pulsanti di controllo -->
|
||||
<div class="flex gap-4 mt-6">
|
||||
<button type="submit" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
|
||||
Salva Impostazioni
|
||||
</button>
|
||||
<button type="button" id="reset-btn" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Anteprima -->
|
||||
<div class="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg shadow">
|
||||
<h2 class="text-xl font-semibold mb-4 text-gray-900 dark:text-gray-100">Anteprima</h2>
|
||||
|
||||
<div id="preview-container" class="border rounded-lg p-4 transition-all duration-300" style="background-color: {{ $settings['bg_color'] }}; color: {{ $settings['text_color'] }};">
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg font-bold">Dashboard Amministratore</h3>
|
||||
<p class="text-sm opacity-75">Benvenuto nel pannello di amministrazione</p>
|
||||
</div>
|
||||
|
||||
<!-- Simulazione sidebar -->
|
||||
<div class="flex gap-4">
|
||||
<div id="sidebar-preview" class="w-32 h-40 rounded p-2 transition-all duration-300" style="background-color: {{ $settings['sidebar_bg_color'] }}; color: {{ $settings['sidebar_text_color'] }};">
|
||||
<div class="text-xs font-bold mb-2">Menu</div>
|
||||
<div class="space-y-1">
|
||||
<div class="text-xs p-1 rounded" style="background-color: {{ $settings['sidebar_accent_color'] }}; opacity: 0.3;">Dashboard</div>
|
||||
<div class="text-xs p-1">Stabili</div>
|
||||
<div class="text-xs p-1">Utenti</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contenuto principale -->
|
||||
<div class="flex-1">
|
||||
<div class="mb-2">
|
||||
<div class="w-full h-6 rounded" style="background-color: {{ $settings['accent_color'] }}; opacity: 0.2;"></div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="w-3/4 h-4 rounded" style="background-color: {{ $settings['text_color'] }}; opacity: 0.2;"></div>
|
||||
<div class="w-1/2 h-4 rounded" style="background-color: {{ $settings['text_color'] }}; opacity: 0.1;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pulsante di esempio -->
|
||||
<button class="mt-4 px-4 py-2 rounded text-white transition-all duration-300" style="background-color: {{ $settings['accent_color'] }};">
|
||||
Pulsante di Esempio
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('color-form');
|
||||
const preview = document.getElementById('preview-container');
|
||||
const sidebarPreview = document.getElementById('sidebar-preview');
|
||||
const colorInputs = form.querySelectorAll('input[type="color"], input[type="checkbox"]');
|
||||
const themeButtons = document.querySelectorAll('.theme-btn');
|
||||
const resetBtn = document.getElementById('reset-btn');
|
||||
|
||||
// Applica dark mode se salvato
|
||||
if (document.getElementById('dark_mode').checked) {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
|
||||
// Aggiorna anteprima in tempo reale
|
||||
function updatePreview() {
|
||||
const bgColor = document.getElementById('bg_color').value;
|
||||
const textColor = document.getElementById('text_color').value;
|
||||
const accentColor = document.getElementById('accent_color').value;
|
||||
const sidebarBgColor = document.getElementById('sidebar_bg_color').value;
|
||||
const sidebarTextColor = document.getElementById('sidebar_text_color').value;
|
||||
const sidebarAccentColor = document.getElementById('sidebar_accent_color').value;
|
||||
const darkMode = document.getElementById('dark_mode').checked;
|
||||
|
||||
preview.style.backgroundColor = bgColor;
|
||||
preview.style.color = textColor;
|
||||
sidebarPreview.style.backgroundColor = sidebarBgColor;
|
||||
sidebarPreview.style.color = sidebarTextColor;
|
||||
|
||||
// Aggiorna pulsante e accent
|
||||
const button = preview.querySelector('button');
|
||||
button.style.backgroundColor = accentColor;
|
||||
|
||||
const accentDiv = sidebarPreview.querySelector('[style*="background-color"]');
|
||||
if (accentDiv) {
|
||||
accentDiv.style.backgroundColor = sidebarAccentColor;
|
||||
}
|
||||
|
||||
// Aggiorna dark mode
|
||||
if (darkMode) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
}
|
||||
|
||||
// Event listeners per anteprima in tempo reale
|
||||
colorInputs.forEach(input => {
|
||||
input.addEventListener('input', updatePreview);
|
||||
input.addEventListener('change', updatePreview);
|
||||
});
|
||||
|
||||
// Temi predefiniti
|
||||
themeButtons.forEach(btn => {
|
||||
btn.addEventListener('click', async function() {
|
||||
const theme = this.dataset.theme;
|
||||
|
||||
try {
|
||||
const response = await fetch('{{ route("admin.impostazioni.theme") }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
|
||||
},
|
||||
body: JSON.stringify({ theme: theme })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success && data.settings) {
|
||||
// Aggiorna i campi del form
|
||||
Object.keys(data.settings).forEach(key => {
|
||||
const input = document.getElementById(key);
|
||||
if (input) input.value = data.settings[key];
|
||||
});
|
||||
|
||||
updatePreview();
|
||||
showMessage('Tema applicato con successo!', 'success');
|
||||
|
||||
// Ricarica la pagina per applicare completamente il tema
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
}
|
||||
} catch (error) {
|
||||
showMessage('Errore nell\'applicazione del tema', 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Salvataggio del form
|
||||
form.addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(this);
|
||||
|
||||
try {
|
||||
const response = await fetch('{{ route("admin.impostazioni.store") }}', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
showMessage(data.message, 'success');
|
||||
// Ricarica la pagina per applicare le modifiche
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
showMessage('Errore nel salvataggio delle impostazioni', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showMessage('Errore nel salvataggio delle impostazioni', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
// Reset
|
||||
resetBtn.addEventListener('click', function() {
|
||||
if (confirm('Sei sicuro di voler ripristinare le impostazioni predefinite?')) {
|
||||
themeButtons[0].click(); // Applica tema default
|
||||
}
|
||||
});
|
||||
|
||||
function showMessage(message, type) {
|
||||
const messageContainer = document.getElementById('message-container');
|
||||
const successDiv = document.getElementById('success-message');
|
||||
const errorDiv = document.getElementById('error-message');
|
||||
const successText = document.getElementById('success-text');
|
||||
const errorText = document.getElementById('error-text');
|
||||
|
||||
// Nascondi tutti i messaggi
|
||||
successDiv.classList.add('hidden');
|
||||
errorDiv.classList.add('hidden');
|
||||
|
||||
if (type === 'success') {
|
||||
successText.textContent = message;
|
||||
successDiv.classList.remove('hidden');
|
||||
} else {
|
||||
errorText.textContent = message;
|
||||
errorDiv.classList.remove('hidden');
|
||||
}
|
||||
|
||||
messageContainer.classList.remove('hidden');
|
||||
|
||||
// Nascondi dopo 5 secondi
|
||||
setTimeout(() => {
|
||||
messageContainer.classList.add('hidden');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Anteprima iniziale
|
||||
updatePreview();
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
|||
144
resources/views/admin/impostazioni/index.blade.php.backup
Normal file
144
resources/views/admin/impostazioni/index.blade.php.backup
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
||||
{{ __('Impostazioni') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 text-gray-900 dark:text-gray-100">
|
||||
|
||||
<div class="mb-6">
|
||||
<h3 class="text-2xl font-bold text-gray-800 dark:text-gray-200">Configurazione Sistema</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mt-2">Gestisci le impostazioni generali dell'applicazione</p>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ route('admin.impostazioni.store') }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
|
||||
<!-- Sezione Applicazione -->
|
||||
<div class="bg-blue-50 dark:bg-blue-900/20 p-6 rounded-lg mb-6">
|
||||
<h4 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">Impostazioni Applicazione</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Nome Applicazione -->
|
||||
<div>
|
||||
<x-input-label for="app_name" :value="__('Nome Applicazione')" />
|
||||
<x-text-input id="app_name" name="app_name" type="text" class="mt-1 block w-full"
|
||||
:value="old('app_name', config('app.name'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('app_name')" />
|
||||
</div>
|
||||
|
||||
<!-- URL Applicazione -->
|
||||
<div>
|
||||
<x-input-label for="app_url" :value="__('URL Applicazione')" />
|
||||
<x-text-input id="app_url" name="app_url" type="url" class="mt-1 block w-full"
|
||||
:value="old('app_url', config('app.url'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('app_url')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sezione Branding -->
|
||||
<div class="bg-green-50 dark:bg-green-900/20 p-6 rounded-lg mb-6">
|
||||
<h4 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">Branding</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Logo Applicazione -->
|
||||
<div>
|
||||
<x-input-label for="app_logo" :value="__('Logo Applicazione')" />
|
||||
<input type="file" id="app_logo" name="app_logo" accept="image/*"
|
||||
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('app_logo')" />
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Formati supportati: JPG, PNG, SVG (max 2MB)</p>
|
||||
</div>
|
||||
|
||||
<!-- Logo Dashboard -->
|
||||
<div>
|
||||
<x-input-label for="dashboard_logo" :value="__('Logo Dashboard')" />
|
||||
<input type="file" id="dashboard_logo" name="dashboard_logo" accept="image/*"
|
||||
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('dashboard_logo')" />
|
||||
</div>
|
||||
|
||||
<!-- Favicon -->
|
||||
<div>
|
||||
<x-input-label for="favicon" :value="__('Favicon')" />
|
||||
<input type="file" id="favicon" name="favicon" accept="image/*"
|
||||
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('favicon')" />
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Formato ICO o PNG 32x32px</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sezione Email -->
|
||||
<div class="bg-yellow-50 dark:bg-yellow-900/20 p-6 rounded-lg mb-6">
|
||||
<h4 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">Configurazione Email</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Email Mittente -->
|
||||
<div>
|
||||
<x-input-label for="mail_from_address" :value="__('Email Mittente')" />
|
||||
<x-text-input id="mail_from_address" name="mail_from_address" type="email" class="mt-1 block w-full"
|
||||
:value="old('mail_from_address', config('mail.from.address'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('mail_from_address')" />
|
||||
</div>
|
||||
|
||||
<!-- Nome Mittente -->
|
||||
<div>
|
||||
<x-input-label for="mail_from_name" :value="__('Nome Mittente')" />
|
||||
<x-text-input id="mail_from_name" name="mail_from_name" type="text" class="mt-1 block w-full"
|
||||
:value="old('mail_from_name', config('mail.from.name'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('mail_from_name')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sezione Pagamenti -->
|
||||
<div class="bg-purple-50 dark:bg-purple-900/20 p-6 rounded-lg mb-6">
|
||||
<h4 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">Configurazione Pagamenti</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<!-- Stripe Key -->
|
||||
<div>
|
||||
<x-input-label for="stripe_key" :value="__('Stripe Publishable Key')" />
|
||||
<x-text-input id="stripe_key" name="stripe_key" type="text" class="mt-1 block w-full"
|
||||
:value="old('stripe_key', config('services.stripe.key'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('stripe_key')" />
|
||||
</div>
|
||||
|
||||
<!-- PayPal Client ID -->
|
||||
<div>
|
||||
<x-input-label for="paypal_client_id" :value="__('PayPal Client ID')" />
|
||||
<x-text-input id="paypal_client_id" name="paypal_client_id" type="text" class="mt-1 block w-full"
|
||||
:value="old('paypal_client_id', config('services.paypal.client_id'))" />
|
||||
<x-input-error class="mt-2" :messages="$errors->get('paypal_client_id')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pulsanti -->
|
||||
<div class="flex items-center justify-end space-x-4">
|
||||
<x-secondary-button type="button" onclick="window.location.reload()">
|
||||
{{ __('Ripristina') }}
|
||||
</x-secondary-button>
|
||||
<x-primary-button>
|
||||
{{ __('Salva Impostazioni') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="mt-4 text-red-600 dark:text-red-400">
|
||||
<ul>
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<nav class="h-full flex flex-col bg-yellow-300 border-r-4 border-indigo-500 py-6 px-2 w-full shadow-xl z-50">
|
||||
<nav class="h-full flex flex-col bg-yellow-300 dark:bg-gray-800 border-r-4 border-indigo-500 dark:border-yellow-500 py-6 px-2 w-full shadow-xl z-50">
|
||||
@php
|
||||
$userRoles = auth()->check() ? auth()->user()->getRoleNames()->toArray() : [];
|
||||
$panelPrefix = '';
|
||||
|
|
@ -40,9 +40,9 @@
|
|||
],
|
||||
];
|
||||
@endphp
|
||||
<div class="px-2 pt-3 pb-2" style="background: var(--sidebar-bg); color: var(--sidebar-text); border-bottom: 2px solid var(--sidebar-accent); position:sticky; top:0; z-index:20;">
|
||||
<div class="px-2 pt-3 pb-2 bg-yellow-200 dark:bg-gray-700 border-b-2 border-indigo-500 dark:border-yellow-500 sticky top-0 z-20">
|
||||
<div class="flex flex-col items-center">
|
||||
<span class="text-xs text-gray-700 mb-1">{{ $annoAttivo }}/{{ $gestione }}</span>
|
||||
<span class="text-xs text-gray-700 dark:text-gray-300 mb-1">{{ $annoAttivo }}/{{ $gestione }}</span>
|
||||
<div class="flex items-center gap-2 bg-yellow-200 dark:bg-gray-800 rounded px-2 py-1 shadow" style="min-width: 160px;">
|
||||
<div class="flex flex-col justify-center items-center mr-1">
|
||||
<button id="prev-stabile" class="w-6 h-6 flex items-center justify-center rounded bg-indigo-500 text-white hover:bg-indigo-700 text-xs mb-1" title="Stabile precedente">
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
{{ $stabileAttivo }}
|
||||
</button>
|
||||
</div>
|
||||
<button id="toggle-darkmode" class="mt-2 px-2 py-1 rounded bg-gray-800 text-yellow-300 hover:bg-gray-900 text-xs flex items-center gap-1" title="Attiva/disattiva modalità scura">
|
||||
<button id="toggle-darkmode" class="mt-2 px-2 py-1 rounded bg-gray-800 dark:bg-yellow-600 text-yellow-300 dark:text-gray-900 hover:bg-gray-900 dark:hover:bg-yellow-700 text-xs flex items-center gap-1" title="Attiva/disattiva modalità scura">
|
||||
<!-- Tabler icon moon -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-moon" width="16" height="16" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 3c.132 0 .263 .003 .393 .008a9 9 0 1 0 9.599 9.599a7 7 0 0 1 -9.992 -9.607z" /></svg>
|
||||
<span>Dark</span>
|
||||
|
|
@ -69,8 +69,8 @@
|
|||
@foreach($mainMenu as $item)
|
||||
@if(array_intersect($item['roles'], $userRoles))
|
||||
@if(Route::has($item['route']))
|
||||
<a href="{{ route($item['route']) }}" class="flex items-center gap-3 px-4 py-2 rounded-lg text-gray-700 hover:bg-indigo-100 hover:text-indigo-700 transition group">
|
||||
<i class="{{ $item['icon'] }} text-lg group-hover:text-indigo-700"></i>
|
||||
<a href="{{ route($item['route']) }}" class="flex items-center gap-3 px-4 py-2 rounded-lg text-gray-700 dark:text-gray-200 hover:bg-indigo-100 dark:hover:bg-gray-700 hover:text-indigo-700 dark:hover:text-yellow-300 transition group">
|
||||
<i class="{{ $item['icon'] }} text-lg group-hover:text-indigo-700 dark:group-hover:text-yellow-300"></i>
|
||||
<span class="font-medium">{{ $item['label'] }}</span>
|
||||
</a>
|
||||
@endif
|
||||
|
|
@ -78,7 +78,7 @@
|
|||
@endforeach
|
||||
</div>
|
||||
<div class="mt-auto pt-4">
|
||||
<button id="submenu-toggle" class="w-full flex items-center justify-center text-gray-400 hover:text-indigo-600 transition" title="Mostra/Nascondi menu">
|
||||
<button id="submenu-toggle" class="w-full flex items-center justify-center text-gray-400 dark:text-gray-500 hover:text-indigo-600 dark:hover:text-yellow-400 transition" title="Mostra/Nascondi menu">
|
||||
<i class="fa-solid fa-bars text-xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -109,12 +109,12 @@
|
|||
</style>
|
||||
<!-- Modale ricerca stabile -->
|
||||
<div id="modal-stabile" class="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50 hidden">
|
||||
<div class="bg-white rounded shadow-lg p-6 w-full max-w-md">
|
||||
<h3 class="text-lg font-bold mb-2">Cerca stabile</h3>
|
||||
<input type="text" id="input-stabile" class="w-full border rounded px-3 py-2 mb-2" placeholder="Digita il nome dello stabile...">
|
||||
<ul id="result-stabile" class="max-h-40 overflow-y-auto"></ul>
|
||||
<div class="bg-white dark:bg-gray-800 rounded shadow-lg p-6 w-full max-w-md">
|
||||
<h3 class="text-lg font-bold mb-2 text-gray-900 dark:text-gray-100">Cerca stabile</h3>
|
||||
<input type="text" id="input-stabile" class="w-full border dark:border-gray-600 rounded px-3 py-2 mb-2 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" placeholder="Digita il nome dello stabile...">
|
||||
<ul id="result-stabile" class="max-h-40 overflow-y-auto text-gray-900 dark:text-gray-100"></ul>
|
||||
<div class="flex justify-end mt-2">
|
||||
<button id="close-modal-stabile" class="px-3 py-1 rounded bg-gray-300 hover:bg-gray-400">Chiudi</button>
|
||||
<button id="close-modal-stabile" class="px-3 py-1 rounded bg-gray-300 dark:bg-gray-600 hover:bg-gray-400 dark:hover:bg-gray-500 text-gray-900 dark:text-gray-100">Chiudi</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -150,7 +150,7 @@ document.getElementById('close-modal-stabile').onclick = function() {
|
|||
document.getElementById('input-stabile').oninput = function(e) {
|
||||
const val = e.target.value.toLowerCase();
|
||||
const results = stabili.filter(s => s.toLowerCase().includes(val));
|
||||
document.getElementById('result-stabile').innerHTML = results.map(s => `<li class='py-1 px-2 hover:bg-yellow-200 cursor-pointer' onclick='selectStabile("${s}")'>${s}</li>`).join('');
|
||||
document.getElementById('result-stabile').innerHTML = results.map(s => `<li class='py-1 px-2 hover:bg-yellow-200 dark:hover:bg-gray-600 cursor-pointer' onclick='selectStabile("${s}")'>${s}</li>`).join('');
|
||||
};
|
||||
window.selectStabile = function(nome) {
|
||||
document.getElementById('current-stabile').textContent = nome;
|
||||
|
|
@ -169,7 +169,7 @@ window.selectStabile = function(nome) {
|
|||
};
|
||||
updateStabile();
|
||||
</script>
|
||||
<footer class="w-full bg-gray-100 border-t border-gray-300 text-xs text-gray-600 text-center py-2 mt-4">
|
||||
<span>NetGesCon © {{ date('Y') }} - <a href="https://github.com/netgescon" class="text-indigo-600 hover:underline">netgescon.github.io</a> - v0.7.0-dev</span>
|
||||
<footer class="w-full bg-gray-100 dark:bg-gray-900 border-t border-gray-300 dark:border-gray-600 text-xs text-gray-600 dark:text-gray-400 text-center py-2 mt-4">
|
||||
<span>NetGesCon © {{ date('Y') }} - <a href="https://github.com/netgescon" class="text-indigo-600 dark:text-yellow-400 hover:underline">netgescon.github.io</a> - v0.7.0-dev</span>
|
||||
</footer>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
|
||||
{{ __('Dashboard') }}
|
||||
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
|
|
@ -10,18 +9,11 @@
|
|||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 text-gray-900 dark:text-gray-100">
|
||||
{{-- Questa dashboard funge da reindirizzamento centrale in base al ruolo --}}
|
||||
{{-- Dashboard generica, nessun redirect JS --}}
|
||||
@auth
|
||||
@if(Auth::user()->hasRole('super-admin'))
|
||||
<script>window.location = "{{ route('superadmin.dashboard') }}";</script>
|
||||
@elseif(Auth::user()->hasRole(['admin', 'amministratore']))
|
||||
<script>window.location = "{{ route('admin.dashboard') }}";</script>
|
||||
@elseif(Auth::user()->hasRole('condomino'))
|
||||
<script>window.location = "{{ route('condomino.dashboard') }}";</script>
|
||||
@else
|
||||
<p>{{ __("You're logged in!") }}</p>
|
||||
<p>Nessun pannello specifico per il tuo ruolo.</p>
|
||||
@endif
|
||||
<p>{{ __("Sei autenticato come: ") }} <strong>{{ Auth::user()->email }}</strong></p>
|
||||
<p>{{ __("Ruoli attivi: ") }} <strong>{{ Auth::user()->getRoleNames()->implode(', ') }}</strong></p>
|
||||
<p>{{ __("Questa è la dashboard generica. Se vedi questa schermata, il tuo ruolo non ha una dashboard dedicata.") }}</p>
|
||||
@else
|
||||
<p>{{ __("You are not logged in.") }}</p>
|
||||
@endauth
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="{{ auth()->check() && userSetting('dark_mode', 'false') === 'true' ? 'dark' : '' }}">
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
|
|
@ -12,26 +12,59 @@
|
|||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />
|
||||
|
||||
<!-- Custom CSS for dark mode -->
|
||||
<link href="{{ asset('css/dark-mode.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@livewireStyles
|
||||
|
||||
@php
|
||||
// Impostazioni utente per colori personalizzati
|
||||
$userBgColor = auth()->check() ? userSetting('bg_color', '#ffffff') : '#ffffff';
|
||||
$userTextColor = auth()->check() ? userSetting('text_color', '#1e293b') : '#1e293b';
|
||||
$userAccentColor = auth()->check() ? userSetting('accent_color', '#6366f1') : '#6366f1';
|
||||
$userSidebarBg = auth()->check() ? userSetting('sidebar_bg_color', '#fde047') : '#fde047';
|
||||
$userSidebarText = auth()->check() ? userSetting('sidebar_text_color', '#1e293b') : '#1e293b';
|
||||
$userSidebarAccent = auth()->check() ? userSetting('sidebar_accent_color', '#6366f1') : '#6366f1';
|
||||
@endphp
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--user-bg-color: {{ $userBgColor }};
|
||||
--user-text-color: {{ $userTextColor }};
|
||||
--user-accent-color: {{ $userAccentColor }};
|
||||
--user-sidebar-bg: {{ $userSidebarBg }};
|
||||
--user-sidebar-text: {{ $userSidebarText }};
|
||||
--user-sidebar-accent: {{ $userSidebarAccent }};
|
||||
}
|
||||
|
||||
/* Applica automaticamente i colori personalizzati */
|
||||
.bg-white { background-color: var(--user-bg-color) !important; }
|
||||
.text-gray-900 { color: var(--user-text-color) !important; }
|
||||
.bg-indigo-600 { background-color: var(--user-accent-color) !important; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="font-sans antialiased">
|
||||
<div class="min-h-screen bg-gray-100 dark:bg-gray-900">
|
||||
@include('layouts.navigation')
|
||||
<div class="min-h-screen bg-gray-100 dark:bg-gray-900 flex">
|
||||
@include('components.menu.sidebar')
|
||||
<div class="flex-1 flex flex-col">
|
||||
@include('layouts.navigation')
|
||||
|
||||
<!-- Page Heading -->
|
||||
@isset($header)
|
||||
<header class="bg-white dark:bg-gray-800 shadow">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
{{ $header }}
|
||||
</div>
|
||||
</header>
|
||||
@endisset
|
||||
<!-- Page Content -->
|
||||
<main>
|
||||
{{ $slot }}
|
||||
</main>
|
||||
<!-- Page Heading -->
|
||||
@isset($header)
|
||||
<header class="bg-white dark:bg-gray-800 shadow">
|
||||
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
{{ $header }}
|
||||
</div>
|
||||
</header>
|
||||
@endisset
|
||||
|
||||
<!-- Page Content -->
|
||||
<main>
|
||||
{{ $slot }}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@livewireScripts
|
||||
</body>
|
||||
|
|
|
|||
291
resources/views/superadmin/impostazioni/index.blade.php
Normal file
291
resources/views/superadmin/impostazioni/index.blade.php
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container mx-auto px-6 py-8 bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold text-gray-900 dark:text-gray-100">Impostazioni Personalizzazione</h1>
|
||||
<p class="text-gray-600 dark:text-gray-400 mt-2">Personalizza i colori e il tema dell'interfaccia</p>
|
||||
</div>
|
||||
|
||||
<!-- Messaggi di successo/errore -->
|
||||
<div id="message-container" class="hidden mb-6">
|
||||
<div id="success-message" class="bg-green-100 dark:bg-green-900 border border-green-400 dark:border-green-600 text-green-700 dark:text-green-300 px-4 py-3 rounded mb-4 hidden">
|
||||
<span id="success-text"></span>
|
||||
</div>
|
||||
<div id="error-message" class="bg-red-100 dark:bg-red-900 border border-red-400 dark:border-red-600 text-red-700 dark:text-red-300 px-4 py-3 rounded mb-4 hidden">
|
||||
<span id="error-text"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
<!-- Pannello di controllo colori -->
|
||||
<div class="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg shadow">
|
||||
<h2 class="text-xl font-semibold mb-4 text-gray-900 dark:text-gray-100">Personalizzazione Colori</h2>
|
||||
|
||||
<form id="color-form" class="space-y-4">
|
||||
@csrf
|
||||
<!-- Dark Mode Toggle -->
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">Modalità Scura</label>
|
||||
<input type="checkbox" id="dark_mode" name="dark_mode" value="true"
|
||||
{{ $settings['dark_mode'] === 'true' ? 'checked' : '' }}
|
||||
class="w-4 h-4 text-indigo-600 bg-gray-100 border-gray-300 rounded focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
|
||||
</div>
|
||||
|
||||
<!-- Colori Principale -->
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mt-6">Tema Principale</h3>
|
||||
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Sfondo</label>
|
||||
<input type="color" id="bg_color" name="bg_color" value="{{ $settings['bg_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Testo</label>
|
||||
<input type="color" id="text_color" name="text_color" value="{{ $settings['text_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Accento</label>
|
||||
<input type="color" id="accent_color" name="accent_color" value="{{ $settings['accent_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Colori Sidebar -->
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mt-6">Sidebar</h3>
|
||||
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Sfondo Sidebar</label>
|
||||
<input type="color" id="sidebar_bg_color" name="sidebar_bg_color" value="{{ $settings['sidebar_bg_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Testo Sidebar</label>
|
||||
<input type="color" id="sidebar_text_color" name="sidebar_text_color" value="{{ $settings['sidebar_text_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Accento Sidebar</label>
|
||||
<input type="color" id="sidebar_accent_color" name="sidebar_accent_color" value="{{ $settings['sidebar_accent_color'] }}"
|
||||
class="w-full h-10 rounded border border-gray-300 dark:border-gray-600">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Temi Predefiniti -->
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mt-6">Temi Predefiniti</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button type="button" class="theme-btn px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600" data-theme="default">Default</button>
|
||||
<button type="button" class="theme-btn px-4 py-2 rounded bg-gray-800 text-white hover:bg-gray-900" data-theme="dark">Dark</button>
|
||||
<button type="button" class="theme-btn px-4 py-2 rounded bg-blue-600 text-white hover:bg-blue-700" data-theme="ocean">Ocean</button>
|
||||
</div>
|
||||
|
||||
<!-- Pulsanti di controllo -->
|
||||
<div class="flex gap-4 mt-6">
|
||||
<button type="submit" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
|
||||
Salva Impostazioni
|
||||
</button>
|
||||
<button type="button" id="reset-btn" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Anteprima -->
|
||||
<div class="bg-gray-50 dark:bg-gray-800 p-6 rounded-lg shadow">
|
||||
<h2 class="text-xl font-semibold mb-4 text-gray-900 dark:text-gray-100">Anteprima</h2>
|
||||
|
||||
<div id="preview-container" class="border rounded-lg p-4 transition-all duration-300" style="background-color: {{ $settings['bg_color'] }}; color: {{ $settings['text_color'] }};">
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg font-bold">Dashboard NetGesCon</h3>
|
||||
<p class="text-sm opacity-75">Benvenuto nel pannello di amministrazione</p>
|
||||
</div>
|
||||
|
||||
<!-- Simulazione sidebar -->
|
||||
<div class="flex gap-4">
|
||||
<div id="sidebar-preview" class="w-32 h-40 rounded p-2 transition-all duration-300" style="background-color: {{ $settings['sidebar_bg_color'] }}; color: {{ $settings['sidebar_text_color'] }};">
|
||||
<div class="text-xs font-bold mb-2">Menu</div>
|
||||
<div class="space-y-1">
|
||||
<div class="text-xs p-1 rounded" style="background-color: {{ $settings['sidebar_accent_color'] }}; opacity: 0.3;">Dashboard</div>
|
||||
<div class="text-xs p-1">Stabili</div>
|
||||
<div class="text-xs p-1">Utenti</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contenuto principale -->
|
||||
<div class="flex-1">
|
||||
<div class="mb-2">
|
||||
<div class="w-full h-6 rounded" style="background-color: {{ $settings['accent_color'] }}; opacity: 0.2;"></div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<div class="w-3/4 h-4 rounded" style="background-color: {{ $settings['text_color'] }}; opacity: 0.2;"></div>
|
||||
<div class="w-1/2 h-4 rounded" style="background-color: {{ $settings['text_color'] }}; opacity: 0.1;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pulsante di esempio -->
|
||||
<button class="mt-4 px-4 py-2 rounded text-white transition-all duration-300" style="background-color: {{ $settings['accent_color'] }};">
|
||||
Pulsante di Esempio
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('color-form');
|
||||
const preview = document.getElementById('preview-container');
|
||||
const sidebarPreview = document.getElementById('sidebar-preview');
|
||||
const colorInputs = form.querySelectorAll('input[type="color"], input[type="checkbox"]');
|
||||
const themeButtons = document.querySelectorAll('.theme-btn');
|
||||
const resetBtn = document.getElementById('reset-btn');
|
||||
|
||||
// Applica dark mode se salvato
|
||||
if (document.getElementById('dark_mode').checked) {
|
||||
document.documentElement.classList.add('dark');
|
||||
}
|
||||
|
||||
// Aggiorna anteprima in tempo reale
|
||||
function updatePreview() {
|
||||
const bgColor = document.getElementById('bg_color').value;
|
||||
const textColor = document.getElementById('text_color').value;
|
||||
const accentColor = document.getElementById('accent_color').value;
|
||||
const sidebarBgColor = document.getElementById('sidebar_bg_color').value;
|
||||
const sidebarTextColor = document.getElementById('sidebar_text_color').value;
|
||||
const sidebarAccentColor = document.getElementById('sidebar_accent_color').value;
|
||||
const darkMode = document.getElementById('dark_mode').checked;
|
||||
|
||||
preview.style.backgroundColor = bgColor;
|
||||
preview.style.color = textColor;
|
||||
sidebarPreview.style.backgroundColor = sidebarBgColor;
|
||||
sidebarPreview.style.color = sidebarTextColor;
|
||||
|
||||
// Aggiorna pulsante e accent
|
||||
const button = preview.querySelector('button');
|
||||
button.style.backgroundColor = accentColor;
|
||||
|
||||
const accentDiv = sidebarPreview.querySelector('[style*="background-color"]');
|
||||
if (accentDiv) {
|
||||
accentDiv.style.backgroundColor = sidebarAccentColor;
|
||||
}
|
||||
|
||||
// Aggiorna dark mode
|
||||
if (darkMode) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
}
|
||||
|
||||
// Event listeners per anteprima in tempo reale
|
||||
colorInputs.forEach(input => {
|
||||
input.addEventListener('input', updatePreview);
|
||||
input.addEventListener('change', updatePreview);
|
||||
});
|
||||
|
||||
// Temi predefiniti
|
||||
themeButtons.forEach(btn => {
|
||||
btn.addEventListener('click', async function() {
|
||||
const theme = this.dataset.theme;
|
||||
|
||||
try {
|
||||
const response = await fetch('{{ route("superadmin.impostazioni.theme") }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
|
||||
},
|
||||
body: JSON.stringify({ theme: theme })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success && data.settings) {
|
||||
// Aggiorna i campi del form
|
||||
Object.keys(data.settings).forEach(key => {
|
||||
const input = document.getElementById(key);
|
||||
if (input) input.value = data.settings[key];
|
||||
});
|
||||
|
||||
updatePreview();
|
||||
showMessage('Tema applicato con successo!', 'success');
|
||||
|
||||
// Ricarica la pagina per applicare completamente il tema
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
}
|
||||
} catch (error) {
|
||||
showMessage('Errore nell\'applicazione del tema', 'error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Salvataggio del form
|
||||
form.addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(this);
|
||||
|
||||
try {
|
||||
const response = await fetch('{{ route("superadmin.impostazioni.store") }}', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
showMessage(data.message, 'success');
|
||||
// Ricarica la pagina per applicare le modifiche
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
showMessage('Errore nel salvataggio delle impostazioni', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
showMessage('Errore nel salvataggio delle impostazioni', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
// Reset
|
||||
resetBtn.addEventListener('click', function() {
|
||||
if (confirm('Sei sicuro di voler ripristinare le impostazioni predefinite?')) {
|
||||
themeButtons[0].click(); // Applica tema default
|
||||
}
|
||||
});
|
||||
|
||||
function showMessage(message, type) {
|
||||
const messageContainer = document.getElementById('message-container');
|
||||
const successDiv = document.getElementById('success-message');
|
||||
const errorDiv = document.getElementById('error-message');
|
||||
const successText = document.getElementById('success-text');
|
||||
const errorText = document.getElementById('error-text');
|
||||
|
||||
// Nascondi tutti i messaggi
|
||||
successDiv.classList.add('hidden');
|
||||
errorDiv.classList.add('hidden');
|
||||
|
||||
if (type === 'success') {
|
||||
successText.textContent = message;
|
||||
successDiv.classList.remove('hidden');
|
||||
} else {
|
||||
errorText.textContent = message;
|
||||
errorDiv.classList.remove('hidden');
|
||||
}
|
||||
|
||||
messageContainer.classList.remove('hidden');
|
||||
|
||||
// Nascondi dopo 5 secondi
|
||||
setTimeout(() => {
|
||||
messageContainer.classList.add('hidden');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Anteprima iniziale
|
||||
updatePreview();
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -64,6 +64,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
|||
// Impostazioni Sistema
|
||||
Route::get('impostazioni', [\App\Http\Controllers\SuperAdmin\ImpostazioniController::class, 'index'])->name('impostazioni.index');
|
||||
Route::post('impostazioni', [\App\Http\Controllers\SuperAdmin\ImpostazioniController::class, 'store'])->name('impostazioni.store');
|
||||
Route::post('impostazioni/theme', [\App\Http\Controllers\SuperAdmin\ImpostazioniController::class, 'theme'])->name('impostazioni.theme');
|
||||
// Gestione Amministratori
|
||||
Route::resource('amministratori', SuperAdminAmministratoreController::class)
|
||||
->except(['show'])
|
||||
|
|
@ -151,6 +152,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
|||
// Impostazioni e API Tokens
|
||||
Route::get('impostazioni', [ImpostazioniController::class, 'index'])->name('impostazioni.index');
|
||||
Route::post('impostazioni', [ImpostazioniController::class, 'store'])->name('impostazioni.store');
|
||||
Route::post('impostazioni/theme', [ImpostazioniController::class, 'theme'])->name('impostazioni.theme');
|
||||
Route::get('api-tokens', [ApiTokenController::class, 'index'])->name('api-tokens.index');
|
||||
Route::post('api-tokens', [ApiTokenController::class, 'store'])->name('api-tokens.store');
|
||||
Route::delete('api-tokens/{token_id}', [ApiTokenController::class, 'destroy'])->name('api-tokens.destroy');
|
||||
|
|
|
|||
21
tailwind.config.js.backup
Normal file
21
tailwind.config.js.backup
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import defaultTheme from 'tailwindcss/defaultTheme';
|
||||
import forms from '@tailwindcss/forms';
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
|
||||
'./storage/framework/views/*.php',
|
||||
'./resources/views/**/*.blade.php',
|
||||
],
|
||||
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['Figtree', ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
plugins: [forms],
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user