netgescon-master/resources/views/admin/theme/index.blade.php
2025-07-20 14:57:25 +00:00

519 lines
26 KiB
PHP

@extends('layouts.admin')
@section('title', 'Personalizzazione Tema - NetGesCon')
@section('content')
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">
<i class="fas fa-palette me-2"></i>
Personalizzazione Tema NetGesCon
</h3>
</div>
<div class="card-body">
<!-- Alert per messaggi -->
<div id="theme-alert" class="alert" style="display: none;"></div>
<!-- Tab Navigation -->
<ul class="nav nav-tabs" id="themeTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="custom-tab" data-bs-toggle="tab" data-bs-target="#custom" type="button" role="tab">
<i class="fas fa-paint-brush me-2"></i>Personalizzato
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="presets-tab" data-bs-toggle="tab" data-bs-target="#presets" type="button" role="tab">
<i class="fas fa-swatchbook me-2"></i>Temi Predefiniti
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="import-export-tab" data-bs-toggle="tab" data-bs-target="#import-export" type="button" role="tab">
<i class="fas fa-exchange-alt me-2"></i>Import/Export
</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content mt-3" id="themeTabContent">
<!-- Personalizzazione Custom -->
<div class="tab-pane fade show active" id="custom" role="tabpanel">
<form id="theme-form">
<div class="row">
<div class="col-md-6">
<h5>Colori Principali</h5>
<div class="mb-3">
<label for="primary_color" class="form-label">Colore Primario</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="primary_color"
name="primary_color" value="{{ $currentTheme['primary_color'] }}" title="Scegli colore primario">
<input type="text" class="form-control" value="{{ $currentTheme['primary_color'] }}"
data-color-input="primary_color">
</div>
</div>
<div class="mb-3">
<label for="secondary_color" class="form-label">Colore Secondario</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="secondary_color"
name="secondary_color" value="{{ $currentTheme['secondary_color'] }}" title="Scegli colore secondario">
<input type="text" class="form-control" value="{{ $currentTheme['secondary_color'] }}"
data-color-input="secondary_color">
</div>
</div>
<div class="mb-3">
<label for="success_color" class="form-label">Colore Successo</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="success_color"
name="success_color" value="{{ $currentTheme['success_color'] }}" title="Scegli colore successo">
<input type="text" class="form-control" value="{{ $currentTheme['success_color'] }}"
data-color-input="success_color">
</div>
</div>
<div class="mb-3">
<label for="danger_color" class="form-label">Colore Pericolo</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="danger_color"
name="danger_color" value="{{ $currentTheme['danger_color'] }}" title="Scegli colore pericolo">
<input type="text" class="form-control" value="{{ $currentTheme['danger_color'] }}"
data-color-input="danger_color">
</div>
</div>
<div class="mb-3">
<label for="warning_color" class="form-label">Colore Avviso</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="warning_color"
name="warning_color" value="{{ $currentTheme['warning_color'] }}" title="Scegli colore avviso">
<input type="text" class="form-control" value="{{ $currentTheme['warning_color'] }}"
data-color-input="warning_color">
</div>
</div>
<div class="mb-3">
<label for="info_color" class="form-label">Colore Info</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="info_color"
name="info_color" value="{{ $currentTheme['info_color'] }}" title="Scegli colore info">
<input type="text" class="form-control" value="{{ $currentTheme['info_color'] }}"
data-color-input="info_color">
</div>
</div>
</div>
<div class="col-md-6">
<h5>Sidebar e Layout</h5>
<div class="mb-3">
<label for="sidebar_bg" class="form-label">Sfondo Sidebar</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="sidebar_bg"
name="sidebar_bg" value="{{ $currentTheme['sidebar_bg'] }}" title="Scegli sfondo sidebar">
<input type="text" class="form-control" value="{{ $currentTheme['sidebar_bg'] }}"
data-color-input="sidebar_bg">
</div>
</div>
<div class="mb-3">
<label for="sidebar_text" class="form-label">Testo Sidebar</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="sidebar_text"
name="sidebar_text" value="{{ $currentTheme['sidebar_text'] }}" title="Scegli colore testo sidebar">
<input type="text" class="form-control" value="{{ $currentTheme['sidebar_text'] }}"
data-color-input="sidebar_text">
</div>
</div>
<div class="mb-3">
<label for="header_bg" class="form-label">Sfondo Header</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="header_bg"
name="header_bg" value="{{ $currentTheme['header_bg'] }}" title="Scegli sfondo header">
<input type="text" class="form-control" value="{{ $currentTheme['header_bg'] }}"
data-color-input="header_bg">
</div>
</div>
<div class="mb-3">
<label for="header_text" class="form-label">Testo Header</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="header_text"
name="header_text" value="{{ $currentTheme['header_text'] }}" title="Scegli colore testo header">
<input type="text" class="form-control" value="{{ $currentTheme['header_text'] }}"
data-color-input="header_text">
</div>
</div>
<div class="mb-3">
<label for="light_color" class="form-label">Colore Chiaro</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="light_color"
name="light_color" value="{{ $currentTheme['light_color'] }}" title="Scegli colore chiaro">
<input type="text" class="form-control" value="{{ $currentTheme['light_color'] }}"
data-color-input="light_color">
</div>
</div>
<div class="mb-3">
<label for="dark_color" class="form-label">Colore Scuro</label>
<div class="input-group">
<input type="color" class="form-control form-control-color" id="dark_color"
name="dark_color" value="{{ $currentTheme['dark_color'] }}" title="Scegli colore scuro">
<input type="text" class="form-control" value="{{ $currentTheme['dark_color'] }}"
data-color-input="dark_color">
</div>
</div>
<div class="mb-3">
<label for="theme_mode" class="form-label">Modalità Tema</label>
<select class="form-select" id="theme_mode" name="theme_mode">
<option value="light" {{ $currentTheme['theme_mode'] == 'light' ? 'selected' : '' }}>Chiaro</option>
<option value="dark" {{ $currentTheme['theme_mode'] == 'dark' ? 'selected' : '' }}>Scuro</option>
</select>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<button type="submit" class="btn btn-primary me-2">
<i class="fas fa-save me-2"></i>Salva Tema
</button>
<button type="button" class="btn btn-secondary me-2" onclick="previewTheme()">
<i class="fas fa-eye me-2"></i>Anteprima
</button>
<button type="button" class="btn btn-outline-danger" onclick="resetTheme()">
<i class="fas fa-undo me-2"></i>Ripristina Default
</button>
</div>
</div>
</form>
</div>
<!-- Temi Predefiniti -->
<div class="tab-pane fade" id="presets" role="tabpanel">
<div class="row">
@foreach($presetThemes as $key => $preset)
<div class="col-md-6 col-lg-4 mb-3">
<div class="card preset-theme-card" data-preset="{{ $key }}">
<div class="card-header d-flex justify-content-between align-items-center"
style="background-color: {{ $preset['colors']['primary_color'] }}; color: white;">
<h6 class="mb-0">{{ $preset['name'] }}</h6>
<i class="fas fa-paint-brush"></i>
</div>
<div class="card-body">
<p class="card-text small">{{ $preset['description'] }}</p>
<div class="d-flex mb-2">
<div class="color-preview me-1" style="background-color: {{ $preset['colors']['primary_color'] }};" title="Primario"></div>
<div class="color-preview me-1" style="background-color: {{ $preset['colors']['secondary_color'] }};" title="Secondario"></div>
<div class="color-preview me-1" style="background-color: {{ $preset['colors']['sidebar_bg'] }};" title="Sidebar"></div>
<div class="color-preview me-1" style="background-color: {{ $preset['colors']['header_bg'] }};" title="Header"></div>
</div>
<button class="btn btn-sm btn-outline-primary w-100" onclick="applyPreset('{{ $key }}')">
<i class="fas fa-download me-1"></i>Applica
</button>
</div>
</div>
</div>
@endforeach
</div>
</div>
<!-- Import/Export -->
<div class="tab-pane fade" id="import-export" role="tabpanel">
<div class="row">
<div class="col-md-6">
<h5>Esporta Tema Corrente</h5>
<p class="text-muted">Salva le tue impostazioni di tema in un file JSON per backup o condivisione.</p>
<button class="btn btn-outline-primary" onclick="exportTheme()">
<i class="fas fa-download me-2"></i>Esporta Tema
</button>
</div>
<div class="col-md-6">
<h5>Importa Tema</h5>
<p class="text-muted">Carica un file JSON di tema precedentemente esportato.</p>
<form id="import-form" enctype="multipart/form-data">
<div class="mb-3">
<input type="file" class="form-control" id="theme_file" name="theme_file" accept=".json">
</div>
<button type="submit" class="btn btn-outline-success">
<i class="fas fa-upload me-2"></i>Importa Tema
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@push('styles')
<style>
.color-preview {
width: 20px;
height: 20px;
border-radius: 3px;
border: 1px solid #ddd;
}
.preset-theme-card {
cursor: pointer;
transition: transform 0.2s;
}
.preset-theme-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.form-control-color {
width: 50px;
height: 38px;
padding: 2px;
}
#custom-theme-preview {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
}
</style>
@endpush
@push('scripts')
<script>
$(document).ready(function() {
// Sincronizza color picker con input text
$('input[type="color"]').on('change', function() {
const colorValue = $(this).val();
const textInput = $(`input[data-color-input="${$(this).attr('name')}"]`);
textInput.val(colorValue);
updatePreview();
});
// Sincronizza input text con color picker
$('input[data-color-input]').on('input', function() {
const colorValue = $(this).val();
if (isValidHexColor(colorValue)) {
const colorPickerName = $(this).attr('data-color-input');
$(`input[name="${colorPickerName}"]`).val(colorValue);
updatePreview();
}
});
// Aggiorna anteprima quando cambia la modalità tema
$('#theme_mode').on('change', updatePreview);
// Form submission
$('#theme-form').on('submit', function(e) {
e.preventDefault();
saveTheme();
});
// Import form submission
$('#import-form').on('submit', function(e) {
e.preventDefault();
importTheme();
});
});
function updatePreview() {
// Implementa anteprima in tempo reale
const formData = new FormData(document.getElementById('theme-form'));
const themeData = Object.fromEntries(formData);
// Applica temporaneamente il CSS per l'anteprima
applyTemporaryCSS(themeData);
}
function applyTemporaryCSS(themeData) {
// Rimuove il CSS temporaneo precedente
$('#temp-theme-css').remove();
// Crea nuovo CSS temporaneo
const css = generateCSS(themeData);
$('<style id="temp-theme-css">' + css + '</style>').appendTo('head');
}
function generateCSS(theme) {
return `
:root {
--netgescon-primary: ${theme.primary_color};
--netgescon-secondary: ${theme.secondary_color};
--netgescon-success: ${theme.success_color};
--netgescon-danger: ${theme.danger_color};
--netgescon-warning: ${theme.warning_color};
--netgescon-info: ${theme.info_color};
--netgescon-light: ${theme.light_color};
--netgescon-dark: ${theme.dark_color};
--netgescon-sidebar-bg: ${theme.sidebar_bg};
--netgescon-sidebar-text: ${theme.sidebar_text};
--netgescon-header-bg: ${theme.header_bg};
--netgescon-header-text: ${theme.header_text};
}
.netgescon-sidebar {
background-color: var(--netgescon-sidebar-bg) !important;
color: var(--netgescon-sidebar-text) !important;
}
.netgescon-sidebar .nav-link {
color: var(--netgescon-sidebar-text) !important;
}
.btn-primary {
background-color: var(--netgescon-primary) !important;
border-color: var(--netgescon-primary) !important;
}
`;
}
function saveTheme() {
const formData = new FormData(document.getElementById('theme-form'));
$.ajax({
url: '{{ route("admin.theme.save") }}',
method: 'POST',
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
showAlert('success', response.message);
// Applica il CSS definitivo
$('#temp-theme-css').remove();
$('<style id="user-theme-css">' + response.css + '</style>').appendTo('head');
},
error: function(xhr) {
const message = xhr.responseJSON?.message || 'Errore nel salvataggio del tema';
showAlert('danger', message);
}
});
}
function applyPreset(presetName) {
$.ajax({
url: '{{ route("admin.theme.preset") }}',
method: 'POST',
data: {
preset: presetName
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
showAlert('success', response.message);
// Aggiorna i campi del form
updateFormFields(response.theme);
// Applica il CSS
$('#temp-theme-css, #user-theme-css').remove();
$('<style id="user-theme-css">' + response.css + '</style>').appendTo('head');
},
error: function(xhr) {
const message = xhr.responseJSON?.message || 'Errore nell\'applicazione del tema';
showAlert('danger', message);
}
});
}
function resetTheme() {
if (confirm('Sei sicuro di voler ripristinare il tema ai valori di default?')) {
$.ajax({
url: '{{ route("admin.theme.reset") }}',
method: 'POST',
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
showAlert('success', response.message);
updateFormFields(response.theme);
$('#temp-theme-css, #user-theme-css').remove();
$('<style id="user-theme-css">' + response.css + '</style>').appendTo('head');
},
error: function(xhr) {
const message = xhr.responseJSON?.message || 'Errore nel ripristino del tema';
showAlert('danger', message);
}
});
}
}
function exportTheme() {
window.location.href = '{{ route("admin.theme.export") }}';
}
function importTheme() {
const formData = new FormData(document.getElementById('import-form'));
$.ajax({
url: '{{ route("admin.theme.import") }}',
method: 'POST',
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
showAlert('success', response.message);
updateFormFields(response.theme);
$('#temp-theme-css, #user-theme-css').remove();
$('<style id="user-theme-css">' + response.css + '</style>').appendTo('head');
$('#import-form')[0].reset();
},
error: function(xhr) {
const message = xhr.responseJSON?.message || 'Errore nell\'importazione del tema';
showAlert('danger', message);
}
});
}
function updateFormFields(theme) {
Object.keys(theme).forEach(key => {
const input = $(`#${key}`);
const textInput = $(`input[data-color-input="${key}"]`);
if (input.length) {
input.val(theme[key]);
}
if (textInput.length) {
textInput.val(theme[key]);
}
});
}
function showAlert(type, message) {
const alert = $('#theme-alert');
alert.removeClass('alert-success alert-danger alert-warning alert-info')
.addClass(`alert-${type}`)
.text(message)
.show();
setTimeout(() => {
alert.hide();
}, 5000);
}
function isValidHexColor(hex) {
return /^#([a-f0-9]{3}){1,2}$/i.test(hex);
}
function previewTheme() {
updatePreview();
showAlert('info', 'Anteprima applicata! Salva per rendere permanenti le modifiche.');
}
</script>
@endpush