feat: complete cookie consent with categories & technical processing
- Full 4-category consent modal: Necesare (locked) / Funcționale / Analitice / Marketing with toggle switches per category - Banner shows simple view first; "Personalizează" opens detailed panel - Consent stored as JSON in localStorage (cookie_consent_v2) - window.cookieConsent object set on load; dispatches cookie-consent-updated / cookie-analytics-granted / cookie-marketing-granted CustomEvents for deferred script loading - Floating 🍪 FAB button lets users re-open settings at any time - Policy page: "Personalizează" button resets consent, reopens modal - Full RO/RU translation for all categories and UI strings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+22
-2
@@ -157,10 +157,30 @@ return [
|
|||||||
'cookie' => [
|
'cookie' => [
|
||||||
'policy_title' => 'Politica de utilizare a fișierelor cookie',
|
'policy_title' => 'Politica de utilizare a fișierelor cookie',
|
||||||
'back' => 'Înapoi',
|
'back' => 'Înapoi',
|
||||||
|
'manage_title' => 'Gestionează setările cookie',
|
||||||
|
|
||||||
|
// Banner (simple view)
|
||||||
'banner_title' => 'Utilizăm fișiere cookie',
|
'banner_title' => 'Utilizăm fișiere cookie',
|
||||||
'banner_body' => 'Folosim module cookie pentru funcționarea site-ului și îmbunătățirea experienței. Cookies strict necesare sunt utilizate fără consimțământ (Legea nr. 195/2024).',
|
'banner_body' => 'Utilizăm cookie-uri pentru funcționarea site-ului și îmbunătățirea experienței dvs. Cookie-urile strict necesare nu necesită consimțământ (Legea nr. 195/2024).',
|
||||||
'read_policy' => 'Politica cookie',
|
'read_policy' => 'Politica cookie',
|
||||||
'accept' => 'Acceptă toate',
|
'accept' => 'Acceptă toate',
|
||||||
'reject' => 'Doar esențiale',
|
'reject' => 'Respinge opționale',
|
||||||
|
'customize' => 'Personalizează',
|
||||||
|
|
||||||
|
// Settings modal
|
||||||
|
'settings_title' => 'Setări cookie',
|
||||||
|
'settings_body' => 'Alegeți ce categorii de cookie-uri acceptați. Puteți modifica preferințele oricând.',
|
||||||
|
'save_settings' => 'Salvează preferințele',
|
||||||
|
'always_on' => 'Întotdeauna activ',
|
||||||
|
|
||||||
|
// Categories
|
||||||
|
'cat_necessary' => 'Cookie-uri strict necesare',
|
||||||
|
'cat_necessary_desc' => 'Indispensabile pentru funcționarea corectă a site-ului: autentificare, sesiune, securitate, preferințe limbă. Nu pot fi dezactivate.',
|
||||||
|
'cat_functional' => 'Cookie-uri funcționale',
|
||||||
|
'cat_functional_desc'=> 'Permit site-ului să rețină alegerile dvs. (limbă, preferințe de afișare) pentru o experiență mai bună.',
|
||||||
|
'cat_analytics' => 'Cookie-uri analitice',
|
||||||
|
'cat_analytics_desc' => 'Ne ajută să înțelegem cum utilizați site-ul (pagini vizitate, surse de trafic) pentru a îmbunătăți serviciile. Date anonimizate.',
|
||||||
|
'cat_marketing' => 'Cookie-uri de marketing',
|
||||||
|
'cat_marketing_desc' => 'Utilizate pentru publicitate relevantă și evaluarea eficienței campaniilor. Pot fi setate de terți (Google Ads etc.).',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
+22
-2
@@ -157,10 +157,30 @@ return [
|
|||||||
'cookie' => [
|
'cookie' => [
|
||||||
'policy_title' => 'Политика использования cookie-файлов',
|
'policy_title' => 'Политика использования cookie-файлов',
|
||||||
'back' => 'Назад',
|
'back' => 'Назад',
|
||||||
|
'manage_title' => 'Управление настройками cookie',
|
||||||
|
|
||||||
|
// Баннер (простой вид)
|
||||||
'banner_title' => 'Мы используем cookie',
|
'banner_title' => 'Мы используем cookie',
|
||||||
'banner_body' => 'Мы используем cookie-файлы для работы сайта и улучшения вашего опыта. Строго необходимые cookie используются без согласия (Закон № 195/2024).',
|
'banner_body' => 'Мы используем cookie-файлы для работы сайта и улучшения вашего опыта. Строго необходимые cookie не требуют согласия (Закон № 195/2024).',
|
||||||
'read_policy' => 'Политика cookie',
|
'read_policy' => 'Политика cookie',
|
||||||
'accept' => 'Принять все',
|
'accept' => 'Принять все',
|
||||||
'reject' => 'Только необходимые',
|
'reject' => 'Отклонить необязательные',
|
||||||
|
'customize' => 'Настроить',
|
||||||
|
|
||||||
|
// Модальное окно настроек
|
||||||
|
'settings_title' => 'Настройки cookie',
|
||||||
|
'settings_body' => 'Выберите, какие категории cookie-файлов вы принимаете. Вы можете изменить настройки в любое время.',
|
||||||
|
'save_settings' => 'Сохранить настройки',
|
||||||
|
'always_on' => 'Всегда активно',
|
||||||
|
|
||||||
|
// Категории
|
||||||
|
'cat_necessary' => 'Строго необходимые cookie',
|
||||||
|
'cat_necessary_desc' => 'Необходимы для корректной работы сайта: аутентификация, сессия, безопасность, языковые настройки. Не могут быть отключены.',
|
||||||
|
'cat_functional' => 'Функциональные cookie',
|
||||||
|
'cat_functional_desc'=> 'Позволяют сайту запоминать ваши предпочтения (язык, настройки отображения) для более удобного использования.',
|
||||||
|
'cat_analytics' => 'Аналитические cookie',
|
||||||
|
'cat_analytics_desc' => 'Помогают нам понять, как вы используете сайт (посещённые страницы, источники трафика), для улучшения сервиса. Данные анонимизированы.',
|
||||||
|
'cat_marketing' => 'Маркетинговые cookie',
|
||||||
|
'cat_marketing_desc' => 'Используются для релевантной рекламы и оценки эффективности кампаний. Могут устанавливаться третьими лицами (Google Ads и др.).',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,90 +1,210 @@
|
|||||||
{{-- Cookie consent banner — localStorage-based, shown once per browser --}}
|
{{-- Full cookie consent — GDPR/Legea 195/2024 compliant --}}
|
||||||
@php
|
@php
|
||||||
$bannerEnabled = data_get($tenant->settings ?? [], 'cookie.banner_enabled', true);
|
$bannerEnabled = data_get($tenant->settings ?? [], 'cookie.banner_enabled', true);
|
||||||
|
$tc = $themeColor ?? '#3B82F6';
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
@if ($bannerEnabled)
|
@if ($bannerEnabled)
|
||||||
|
<style>
|
||||||
|
[x-cloak]{display:none!important}
|
||||||
|
.ck-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:10000;display:flex;align-items:flex-end;justify-content:center;padding:0}
|
||||||
|
@media(min-width:600px){.ck-overlay{align-items:center;padding:20px}}
|
||||||
|
.ck-modal{background:#fff;width:100%;max-width:560px;border-radius:16px 16px 0 0;padding:24px 20px 20px;max-height:90vh;overflow-y:auto;box-shadow:0 -8px 40px rgba(0,0,0,.18);font-family:system-ui,-apple-system,'Segoe UI',sans-serif}
|
||||||
|
@media(min-width:600px){.ck-modal{border-radius:16px;max-height:80vh}}
|
||||||
|
.ck-modal h2{font-size:17px;font-weight:700;color:#111827;margin-bottom:6px}
|
||||||
|
.ck-modal .ck-intro{font-size:13px;color:#6b7280;margin-bottom:16px;line-height:1.5}
|
||||||
|
.ck-cat{border:1px solid #e5e7eb;border-radius:10px;padding:14px 14px 12px;margin-bottom:8px}
|
||||||
|
.ck-cat-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
|
||||||
|
.ck-cat-head label{font-size:14px;font-weight:600;color:#111827;cursor:pointer;flex:1}
|
||||||
|
.ck-cat p{font-size:12px;color:#6b7280;margin-top:8px;line-height:1.5}
|
||||||
|
.ck-toggle{position:relative;width:40px;height:22px;flex-shrink:0}
|
||||||
|
.ck-toggle input{opacity:0;width:0;height:0;position:absolute}
|
||||||
|
.ck-slider{position:absolute;inset:0;border-radius:22px;background:#d1d5db;transition:background .2s;cursor:pointer}
|
||||||
|
.ck-slider:before{content:'';position:absolute;width:16px;height:16px;left:3px;top:3px;border-radius:50%;background:#fff;transition:transform .2s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
|
||||||
|
input:checked+.ck-slider{background:{{ $tc }}}
|
||||||
|
input:checked+.ck-slider:before{transform:translateX(18px)}
|
||||||
|
input:disabled+.ck-slider{opacity:.6;cursor:default}
|
||||||
|
.ck-badge{font-size:11px;background:#f3f4f6;color:#6b7280;border-radius:4px;padding:1px 7px;font-weight:500}
|
||||||
|
.ck-badge.always{background:#dcfce7;color:#166534}
|
||||||
|
.ck-btns{display:flex;gap:8px;margin-top:16px;flex-wrap:wrap}
|
||||||
|
.ck-btn{flex:1;min-width:120px;padding:10px 12px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer;border:none;white-space:nowrap;text-align:center}
|
||||||
|
.ck-btn-primary{background:{{ $tc }};color:#fff}
|
||||||
|
.ck-btn-secondary{background:#f3f4f6;color:#374151;border:1px solid #e5e7eb}
|
||||||
|
.ck-btn-ghost{background:transparent;color:#6b7280;border:1px solid #d1d5db}
|
||||||
|
.ck-link{color:{{ $tc }};text-decoration:none;font-size:12px}
|
||||||
|
.ck-link:hover{opacity:.8}
|
||||||
|
.ck-footer{display:flex;justify-content:space-between;align-items:center;margin-top:14px;padding-top:12px;border-top:1px solid #f3f4f6;flex-wrap:wrap;gap:8px}
|
||||||
|
/* Floating re-open button */
|
||||||
|
.ck-fab{position:fixed;bottom:16px;left:16px;z-index:9000;background:#fff;border:1px solid #e5e7eb;border-radius:50%;width:44px;height:44px;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.12);font-size:20px;transition:box-shadow .15s}
|
||||||
|
.ck-fab:hover{box-shadow:0 4px 16px rgba(0,0,0,.18)}
|
||||||
|
@media(prefers-color-scheme:dark){
|
||||||
|
.ck-modal{background:#1e293b;color:#f1f5f9}
|
||||||
|
.ck-modal h2{color:#f1f5f9}
|
||||||
|
.ck-modal .ck-intro{color:#94a3b8}
|
||||||
|
.ck-cat{border-color:#334155}
|
||||||
|
.ck-cat-head label{color:#f1f5f9}
|
||||||
|
.ck-cat p{color:#94a3b8}
|
||||||
|
.ck-slider{background:#475569}
|
||||||
|
.ck-badge{background:#334155;color:#94a3b8}
|
||||||
|
.ck-badge.always{background:#14532d;color:#86efac}
|
||||||
|
.ck-btn-secondary{background:#334155;color:#f1f5f9;border-color:#475569}
|
||||||
|
.ck-btn-ghost{color:#94a3b8;border-color:#475569}
|
||||||
|
.ck-footer{border-color:#334155}
|
||||||
|
.ck-fab{background:#1e293b;border-color:#334155;color:#f1f5f9}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
x-data="{
|
x-data="cookieConsent()"
|
||||||
show: false,
|
x-init="init()"
|
||||||
init() {
|
|
||||||
if (!localStorage.getItem('cookie_consent')) {
|
|
||||||
this.show = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
accept() {
|
|
||||||
localStorage.setItem('cookie_consent', 'accepted');
|
|
||||||
this.show = false;
|
|
||||||
},
|
|
||||||
reject() {
|
|
||||||
localStorage.setItem('cookie_consent', 'essential_only');
|
|
||||||
this.show = false;
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
x-show="show"
|
|
||||||
x-cloak
|
|
||||||
x-transition:enter="transition ease-out duration-300"
|
|
||||||
x-transition:enter-start="opacity-0 translate-y-4"
|
|
||||||
x-transition:enter-end="opacity-100 translate-y-0"
|
|
||||||
x-transition:leave="transition ease-in duration-200"
|
|
||||||
x-transition:leave-start="opacity-100 translate-y-0"
|
|
||||||
x-transition:leave-end="opacity-0 translate-y-4"
|
|
||||||
style="
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 9999;
|
|
||||||
background: #1f2937;
|
|
||||||
color: #f9fafb;
|
|
||||||
padding: 16px 20px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 16px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
box-shadow: 0 -4px 20px rgba(0,0,0,.25);
|
|
||||||
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 1.5;
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<div style="flex:1;min-width:200px;">
|
{{-- Backdrop + Modal --}}
|
||||||
<span style="font-weight:600;margin-right:6px;">🍪 {{ __('portal.cookie.banner_title') }}</span>
|
<div class="ck-overlay" x-show="open" x-cloak @click.self="open=false">
|
||||||
|
<div class="ck-modal" @click.stop>
|
||||||
|
<div x-show="!showDetails">
|
||||||
|
{{-- Simple banner view --}}
|
||||||
|
<h2>🍪 {{ __('portal.cookie.banner_title') }}</h2>
|
||||||
|
<p class="ck-intro">
|
||||||
{{ __('portal.cookie.banner_body') }}
|
{{ __('portal.cookie.banner_body') }}
|
||||||
<a href="{{ route('cookie.policy') }}" style="color:#93c5fd;text-decoration:underline;margin-left:4px;" target="_blank" rel="noopener">
|
<a href="{{ route('cookie.policy') }}" class="ck-link" target="_blank" rel="noopener">{{ __('portal.cookie.read_policy') }} →</a>
|
||||||
{{ __('portal.cookie.read_policy') }}
|
</p>
|
||||||
</a>
|
<div class="ck-btns">
|
||||||
</div>
|
<button class="ck-btn ck-btn-primary" @click="acceptAll()">{{ __('portal.cookie.accept') }}</button>
|
||||||
<div style="display:flex;gap:8px;flex-shrink:0;flex-wrap:wrap;">
|
<button class="ck-btn ck-btn-secondary" @click="showDetails=true">{{ __('portal.cookie.customize') }}</button>
|
||||||
<button
|
<button class="ck-btn ck-btn-ghost" @click="rejectAll()">{{ __('portal.cookie.reject') }}</button>
|
||||||
@click="reject()"
|
|
||||||
style="
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: 1px solid #6b7280;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: transparent;
|
|
||||||
color: #d1d5db;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
white-space: nowrap;
|
|
||||||
"
|
|
||||||
>{{ __('portal.cookie.reject') }}</button>
|
|
||||||
<button
|
|
||||||
@click="accept()"
|
|
||||||
style="
|
|
||||||
padding: 8px 20px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 6px;
|
|
||||||
background: {{ $themeColor ?? '#3B82F6' }};
|
|
||||||
color: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 600;
|
|
||||||
white-space: nowrap;
|
|
||||||
"
|
|
||||||
>{{ __('portal.cookie.accept') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div x-show="showDetails" x-cloak>
|
||||||
|
{{-- Detailed categories view --}}
|
||||||
|
<h2>{{ __('portal.cookie.settings_title') }}</h2>
|
||||||
|
<p class="ck-intro">{{ __('portal.cookie.settings_body') }}</p>
|
||||||
|
|
||||||
|
{{-- Necessary --}}
|
||||||
|
<div class="ck-cat">
|
||||||
|
<div class="ck-cat-head">
|
||||||
|
<label>{{ __('portal.cookie.cat_necessary') }}</label>
|
||||||
|
<span class="ck-badge always">{{ __('portal.cookie.always_on') }}</span>
|
||||||
|
<label class="ck-toggle">
|
||||||
|
<input type="checkbox" checked disabled>
|
||||||
|
<span class="ck-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p>{{ __('portal.cookie.cat_necessary_desc') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Functional --}}
|
||||||
|
<div class="ck-cat">
|
||||||
|
<div class="ck-cat-head">
|
||||||
|
<label for="ck_func">{{ __('portal.cookie.cat_functional') }}</label>
|
||||||
|
<label class="ck-toggle">
|
||||||
|
<input id="ck_func" type="checkbox" x-model="consent.functional">
|
||||||
|
<span class="ck-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p>{{ __('portal.cookie.cat_functional_desc') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Analytics --}}
|
||||||
|
<div class="ck-cat">
|
||||||
|
<div class="ck-cat-head">
|
||||||
|
<label for="ck_anal">{{ __('portal.cookie.cat_analytics') }}</label>
|
||||||
|
<label class="ck-toggle">
|
||||||
|
<input id="ck_anal" type="checkbox" x-model="consent.analytics">
|
||||||
|
<span class="ck-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p>{{ __('portal.cookie.cat_analytics_desc') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Marketing --}}
|
||||||
|
<div class="ck-cat">
|
||||||
|
<div class="ck-cat-head">
|
||||||
|
<label for="ck_mktg">{{ __('portal.cookie.cat_marketing') }}</label>
|
||||||
|
<label class="ck-toggle">
|
||||||
|
<input id="ck_mktg" type="checkbox" x-model="consent.marketing">
|
||||||
|
<span class="ck-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<p>{{ __('portal.cookie.cat_marketing_desc') }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ck-btns">
|
||||||
|
<button class="ck-btn ck-btn-primary" @click="saveSettings()">{{ __('portal.cookie.save_settings') }}</button>
|
||||||
|
<button class="ck-btn ck-btn-secondary" @click="acceptAll()">{{ __('portal.cookie.accept') }}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ck-footer">
|
||||||
|
<a href="{{ route('cookie.policy') }}" class="ck-link" target="_blank" rel="noopener">{{ __('portal.cookie.read_policy') }}</a>
|
||||||
|
<button class="ck-btn-ghost" style="border:none;background:transparent;font-size:12px;color:#6b7280;cursor:pointer;" @click="showDetails=false">← {{ __('portal.cookie.back') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Floating re-open button (shown after consent given) --}}
|
||||||
|
<button class="ck-fab" x-show="!open && resolved" x-cloak @click="open=true;showDetails=true" title="{{ __('portal.cookie.manage_title') }}">🍪</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function cookieConsent() {
|
||||||
|
return {
|
||||||
|
open: false,
|
||||||
|
resolved: false,
|
||||||
|
showDetails: false,
|
||||||
|
consent: { necessary: true, functional: true, analytics: false, marketing: false },
|
||||||
|
|
||||||
|
init() {
|
||||||
|
const saved = localStorage.getItem('cookie_consent_v2');
|
||||||
|
if (saved) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(saved);
|
||||||
|
this.consent = { necessary: true, ...data };
|
||||||
|
this.resolved = true;
|
||||||
|
this._apply();
|
||||||
|
} catch(e) {
|
||||||
|
this.open = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Small delay so page content loads first
|
||||||
|
setTimeout(() => { this.open = true; }, 600);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
acceptAll() {
|
||||||
|
this.consent = { necessary: true, functional: true, analytics: true, marketing: true };
|
||||||
|
this._save();
|
||||||
|
},
|
||||||
|
|
||||||
|
rejectAll() {
|
||||||
|
this.consent = { necessary: true, functional: false, analytics: false, marketing: false };
|
||||||
|
this._save();
|
||||||
|
},
|
||||||
|
|
||||||
|
saveSettings() {
|
||||||
|
this.consent.necessary = true;
|
||||||
|
this._save();
|
||||||
|
this.showDetails = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_save() {
|
||||||
|
localStorage.setItem('cookie_consent_v2', JSON.stringify(this.consent));
|
||||||
|
this.resolved = true;
|
||||||
|
this.open = false;
|
||||||
|
this._apply();
|
||||||
|
},
|
||||||
|
|
||||||
|
_apply() {
|
||||||
|
window.cookieConsent = { ...this.consent };
|
||||||
|
window.dispatchEvent(new CustomEvent('cookie-consent-updated', { detail: { ...this.consent } }));
|
||||||
|
// Load deferred analytics/marketing scripts based on consent
|
||||||
|
if (this.consent.analytics) {
|
||||||
|
document.dispatchEvent(new CustomEvent('cookie-analytics-granted'));
|
||||||
|
}
|
||||||
|
if (this.consent.marketing) {
|
||||||
|
document.dispatchEvent(new CustomEvent('cookie-marketing-granted'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@@ -13,13 +13,16 @@
|
|||||||
header { background: {{ $themeColor }}; color: #fff; padding: 28px 16px; text-align: center; }
|
header { background: {{ $themeColor }}; color: #fff; padding: 28px 16px; text-align: center; }
|
||||||
header img { max-height: 48px; margin-bottom: 10px; display: block; margin-inline: auto; }
|
header img { max-height: 48px; margin-bottom: 10px; display: block; margin-inline: auto; }
|
||||||
header h1 { font-size: 20px; font-weight: 700; }
|
header h1 { font-size: 20px; font-weight: 700; }
|
||||||
.wrap { max-width: 760px; margin: 0 auto; padding: 24px 16px 64px; }
|
.wrap { max-width: 760px; margin: 0 auto; padding: 24px 16px 80px; }
|
||||||
.card { background: #fff; border-radius: 12px; padding: 28px 24px; margin-top: 16px; box-shadow: 0 1px 3px rgba(0,0,0,.05); }
|
.card { background: #fff; border-radius: 12px; padding: 28px 24px; margin-top: 16px; box-shadow: 0 1px 3px rgba(0,0,0,.05); }
|
||||||
.card h2 { font-size: 15px; font-weight: 700; margin-bottom: 12px; color: {{ $themeColor }}; letter-spacing: .02em; }
|
.card-title { font-size: 16px; font-weight: 700; margin-bottom: 14px; color: {{ $themeColor }}; }
|
||||||
.policy-text { font-size: 14px; white-space: pre-wrap; color: #374151; line-height: 1.7; }
|
.policy-text { font-size: 13.5px; white-space: pre-wrap; color: #374151; line-height: 1.75; }
|
||||||
.back-link { display: inline-flex; align-items: center; gap: 6px; color: {{ $themeColor }}; text-decoration: none; font-size: 14px; font-weight: 500; margin-bottom: 8px; }
|
.back-link { display: inline-flex; align-items: center; gap: 6px; color: {{ $themeColor }}; text-decoration: none; font-size: 14px; font-weight: 500; margin-bottom: 8px; }
|
||||||
.back-link:hover { opacity: .8; }
|
.back-link:hover { opacity: .8; }
|
||||||
|
.manage-btn { display: inline-flex; align-items: center; gap: 6px; background: {{ $themeColor }}; color: #fff; border: none; padding: 10px 20px; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; text-decoration: none; }
|
||||||
|
.manage-btn:hover { opacity: .9; }
|
||||||
footer { text-align: center; padding: 24px 16px; color: #9ca3af; font-size: 12px; }
|
footer { text-align: center; padding: 24px 16px; color: #9ca3af; font-size: 12px; }
|
||||||
|
[x-cloak] { display: none !important; }
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
body { background: #0f172a; color: #e5e7eb; }
|
body { background: #0f172a; color: #e5e7eb; }
|
||||||
.card { background: #1e293b; box-shadow: none; }
|
.card { background: #1e293b; box-shadow: none; }
|
||||||
@@ -27,6 +30,7 @@
|
|||||||
footer { color: #64748b; }
|
footer { color: #64748b; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
@@ -37,19 +41,40 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<a href="{{ url()->previous('/') }}" class="back-link">
|
<a href="javascript:history.back()" class="back-link">
|
||||||
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" viewBox="0 0 24 24">
|
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" viewBox="0 0 24 24">
|
||||||
<path stroke-linecap="round" d="M15 19l-7-7 7-7"/>
|
<path stroke-linecap="round" d="M15 19l-7-7 7-7"/>
|
||||||
</svg>
|
</svg>
|
||||||
{{ __('portal.cookie.back') }}
|
{{ __('portal.cookie.back') }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card" style="margin-bottom:12px;">
|
||||||
<h2>{{ __('portal.cookie.policy_title') }}</h2>
|
<p class="card-title">{{ __('portal.cookie.policy_title') }}</p>
|
||||||
<p class="policy-text">{{ $policyText }}</p>
|
<p class="policy-text">{{ $policyText }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="card" style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;">
|
||||||
|
<div>
|
||||||
|
<p style="font-size:14px;font-weight:600;color:#111827;margin-bottom:2px;">{{ __('portal.cookie.manage_title') }}</p>
|
||||||
|
<p style="font-size:13px;color:#6b7280;">{{ __('portal.cookie.settings_body') }}</p>
|
||||||
|
</div>
|
||||||
|
<button class="manage-btn" onclick="openCookieSettings()">
|
||||||
|
🍪 {{ __('portal.cookie.customize') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<footer>{{ __('portal.common.powered_by') }}</footer>
|
<footer>{{ __('portal.common.powered_by') }}</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@php $themeColor = $themeColor ?? '#3B82F6'; @endphp
|
||||||
|
@include('partials.cookie-banner')
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function openCookieSettings() {
|
||||||
|
// Reset consent so the banner re-appears with settings panel open
|
||||||
|
localStorage.removeItem('cookie_consent_v2');
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -231,7 +231,6 @@
|
|||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@php $themeColor = $tenant->settings['theme_color'] ?? '#3B82F6'; @endphp
|
|
||||||
@include('partials.cookie-banner')
|
@include('partials.cookie-banner')
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user