166 lines
8.0 KiB
Plaintext
166 lines
8.0 KiB
Plaintext
@namespace MidrandBooks.Components.Layout
|
|
@using MidrandBooks.Components.Pages
|
|
@inject IJSRuntime JSRuntime
|
|
|
|
@if (ShowBanner || ShowPrivacyModal)
|
|
{
|
|
@if (ShowBanner)
|
|
{
|
|
<div id="cookie-acceptance-banner"
|
|
class="fixed bottom-4 left-4 z-40 max-w-sm w-[calc(100vw-2rem)] sm:w-[380px] bg-slate-900/95 backdrop-blur-md border border-white/10 rounded-2xl p-4 shadow-2xl flex flex-col gap-3 animate-in slide-in-from-bottom-8 fade-in duration-500">
|
|
<!-- Accent Line -->
|
|
<div class="absolute top-0 left-6 right-6 h-0.5 bg-gradient-to-r from-violet-500/0 via-violet-500/50 to-violet-500/0"></div>
|
|
|
|
<div class="flex items-start gap-3">
|
|
<!-- Visual Icon -->
|
|
<div class="h-9 w-9 rounded-xl bg-violet-500/10 border border-violet-500/20 text-violet-400 flex items-center justify-center flex-shrink-0">
|
|
<svg class="h-5 w-5 animate-pulse" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="10" />
|
|
<path d="M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5" />
|
|
<path d="M8.5 8.5v.01" />
|
|
<path d="M16 15.5v.01" />
|
|
<path d="M12 12v.01" />
|
|
<path d="M11 16v.01" />
|
|
<path d="M15 11v.01" />
|
|
</svg>
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<h4 class="text-xs font-mono font-bold uppercase tracking-wider text-white">
|
|
Cookie & POPIA Protocol
|
|
</h4>
|
|
<p class="text-[11px] text-slate-300 leading-relaxed font-medium">
|
|
We utilize essential identifiers to facilitate secure electronic catalog licensing, sandboxed media playbacks, and cryptographic PayFast gateway handshake handoffs under <strong class="text-violet-300">Lite Charms (Pty) Ltd</strong>.
|
|
</p>
|
|
</div>
|
|
|
|
<button @onclick="DismissBanner"
|
|
class="text-slate-400 hover:text-white transition-colors cursor-pointer p-0.5"
|
|
aria-label="Dismiss banner">
|
|
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Action Links & Buttons -->
|
|
<div class="flex items-center justify-between mt-1 pt-2.5 border-t border-white/5">
|
|
<button @onclick="OpenPrivacyModal"
|
|
class="text-[11px] font-semibold text-violet-400 hover:text-violet-300 underline cursor-pointer flex items-center gap-1 focus:outline-none">
|
|
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
|
</svg>
|
|
Privacy Policy
|
|
</button>
|
|
|
|
<div class="flex items-center gap-2">
|
|
<button @onclick="AcceptCookies"
|
|
class="bg-violet-600 hover:bg-violet-500 text-white rounded-xl py-1.5 px-3.5 text-[10px] font-mono font-bold uppercase tracking-wider transition-all cursor-pointer shadow-lg shadow-violet-600/15 hover:scale-[1.02] active:scale-[0.98]">
|
|
Accept All
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@if (ShowPrivacyModal)
|
|
{
|
|
<div id="cookie-privacy-modal-overlay"
|
|
class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-slate-950/80 backdrop-blur-md overflow-y-auto">
|
|
<div id="cookie-privacy-modal-content"
|
|
class="relative w-full max-w-5xl bg-slate-950 border border-white/10 rounded-3xl shadow-2xl overflow-hidden max-h-[90vh] flex flex-col animate-in zoom-in-95 duration-200">
|
|
<!-- Upper Highlight Bar -->
|
|
<div class="absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-violet-500 via-indigo-500 to-violet-500" />
|
|
|
|
<!-- Modal Header -->
|
|
<div class="flex items-center justify-between px-6 py-4 border-b border-white/10 bg-slate-900/40 relative z-10 flex-shrink-0">
|
|
<div class="flex items-center gap-2 text-white">
|
|
<svg class="h-5 w-5 text-violet-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
|
</svg>
|
|
<span class="font-mono text-xs font-bold uppercase tracking-wider text-slate-300">
|
|
Secure Legal Document Portal
|
|
</span>
|
|
</div>
|
|
<button @onclick="ClosePrivacyModal"
|
|
class="p-1.5 rounded-xl border border-white/10 bg-white/5 text-slate-400 hover:text-white shadow-sm hover:scale-105 transition-all cursor-pointer"
|
|
aria-label="Close modal">
|
|
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Modal Scrollable Body -->
|
|
<div class="flex-1 overflow-y-auto bg-slate-950/50 p-4 sm:p-6 md:p-8">
|
|
<div class="max-w-4xl mx-auto -my-10">
|
|
<Privacy />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal Footer -->
|
|
<div class="px-6 py-4 border-t border-white/10 bg-slate-900/40 flex items-center justify-end flex-shrink-0">
|
|
<button @onclick="ClosePrivacyModal"
|
|
class="bg-white/5 hover:bg-white/10 text-slate-300 border border-white/10 rounded-xl py-2 px-5 text-xs font-mono font-bold uppercase tracking-wider transition-all cursor-pointer">
|
|
Close Document
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
|
|
@code {
|
|
private bool ShowBanner { get; set; } = false;
|
|
private bool ShowPrivacyModal { get; set; } = false;
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (firstRender)
|
|
{
|
|
try
|
|
{
|
|
var isAccepted = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "midrandbooks_cookie_accepted");
|
|
if (isAccepted != "true")
|
|
{
|
|
await Task.Delay(1500);
|
|
ShowBanner = true;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Fail gracefully if localStorage is blocked
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task AcceptCookies()
|
|
{
|
|
try
|
|
{
|
|
await JSRuntime.InvokeVoidAsync("localStorage.setItem", "midrandbooks_cookie_accepted", "true");
|
|
}
|
|
catch
|
|
{
|
|
// Fail gracefully
|
|
}
|
|
ShowBanner = false;
|
|
}
|
|
|
|
private void DismissBanner()
|
|
{
|
|
ShowBanner = false;
|
|
}
|
|
|
|
private void OpenPrivacyModal()
|
|
{
|
|
ShowPrivacyModal = true;
|
|
}
|
|
|
|
private void ClosePrivacyModal()
|
|
{
|
|
ShowPrivacyModal = false;
|
|
}
|
|
}
|