260 lines
8.5 KiB
PHP
260 lines
8.5 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
|
|
@php
|
|
$config = app(\App\Services\SystemConfig\SystemConfigService::class);
|
|
$settings = $config->all();
|
|
$title = $settings['maintenance_mode_title'] ?? 'Under Maintenance';
|
|
$message = $settings['maintenance_mode_message'] ?? 'We are currently performing scheduled maintenance. We will be back shortly!';
|
|
$maintenance_image = $settings['maintenance_mode_image'] ?? null;
|
|
$app_favicon = $settings['app_favicon'] ?? '';
|
|
@endphp
|
|
|
|
<title>{{ $title }}</title>
|
|
<link rel="icon" type="image/png" href="{{ asset($app_favicon) }}?v={{ time() }}">
|
|
|
|
{{-- Fonts & Icons --}}
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;800&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
|
<link href="{{ asset('assets/css/app.css') }}" rel="stylesheet">
|
|
|
|
<style>
|
|
body {
|
|
font-family: 'Outfit', sans-serif;
|
|
background-color: #fcfcfc;
|
|
margin: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 100vh;
|
|
color: #1e1e1e;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.main-bg-figure {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
z-index: -1;
|
|
}
|
|
|
|
.main-bg-figure img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
filter: invert(1) opacity(0.05);
|
|
}
|
|
|
|
.maintenance-container {
|
|
text-align: center;
|
|
max-width: 480px;
|
|
padding: 2rem;
|
|
position: relative;
|
|
z-index: 10;
|
|
}
|
|
|
|
/* Status Badge */
|
|
.status-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
background: white;
|
|
padding: 8px 18px;
|
|
border-radius: 50px;
|
|
border: 1px solid #eee;
|
|
margin-bottom: 40px;
|
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.03);
|
|
}
|
|
|
|
.status-dot {
|
|
width: 8px;
|
|
height: 8px;
|
|
background-color: #ff3b30;
|
|
border-radius: 50%;
|
|
margin-right: 10px;
|
|
animation: pulse-red 2s infinite;
|
|
}
|
|
|
|
@keyframes pulse-red {
|
|
0% {
|
|
box-shadow: 0 0 0 0 rgba(255, 59, 48, 0.4);
|
|
}
|
|
|
|
70% {
|
|
box-shadow: 0 0 0 8px rgba(255, 59, 48, 0);
|
|
}
|
|
|
|
100% {
|
|
box-shadow: 0 0 0 0 rgba(255, 59, 48, 0);
|
|
}
|
|
}
|
|
|
|
.status-text {
|
|
font-size: 0.75rem;
|
|
font-weight: 700;
|
|
color: #444;
|
|
letter-spacing: 0.5px;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
/* Logo & Text */
|
|
.app-logo {
|
|
max-height: 90px;
|
|
margin-bottom: 25px;
|
|
display: block;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
|
|
.app-title {
|
|
font-weight: 800;
|
|
font-size: 2.2rem;
|
|
margin-bottom: 15px;
|
|
letter-spacing: -0.5px;
|
|
}
|
|
|
|
.app-message {
|
|
color: #7a8ba3;
|
|
line-height: 1.6;
|
|
font-size: 1rem;
|
|
margin-bottom: 40px;
|
|
}
|
|
|
|
/* Black Countdown Boxes (Requested) */
|
|
.countdown-wrapper {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.countdown-box {
|
|
background-color: #1e1e1e;
|
|
/* Kotak Hitam */
|
|
color: white;
|
|
width: 75px;
|
|
height: 75px;
|
|
border-radius: 20px;
|
|
/* Sangat Bulat */
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.cd-val {
|
|
font-size: 1.5rem;
|
|
font-weight: 800;
|
|
line-height: 1;
|
|
}
|
|
|
|
.cd-label {
|
|
font-size: 0.6rem;
|
|
font-weight: 600;
|
|
opacity: 0.6;
|
|
text-transform: uppercase;
|
|
margin-top: 4px;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<figure class="main-bg-figure">
|
|
<img src="{{ asset('assets/img/background-image/bg1.png') }}" alt="Bg">
|
|
</figure>
|
|
|
|
<div class="maintenance-container">
|
|
<div class="status-badge">
|
|
<div class="status-dot"></div>
|
|
<div class="status-text">{{ __('Under Maintenance') }}</div>
|
|
</div>
|
|
|
|
@php
|
|
$display_img = null;
|
|
if (!empty($maintenance_image)) {
|
|
$display_img = str_starts_with($maintenance_image, 'assets/') ? asset($maintenance_image) : asset('storage/' . $maintenance_image);
|
|
} elseif (!empty($settings['app_logo'])) {
|
|
$display_img = str_starts_with($settings['app_logo'], 'assets/') ? asset($settings['app_logo']) : asset('storage/' . $settings['app_logo']);
|
|
}
|
|
@endphp
|
|
|
|
<div class="logo-wrapper">
|
|
@if($display_img)
|
|
<img src="{{ $display_img }}?v={{ time() }}" class="app-logo" alt="Logo">
|
|
@else
|
|
<h1 class="fw-bold" style="font-size: 3.5rem; margin-bottom: 20px; font-weight: 800;">bii.</h1>
|
|
@endif
|
|
</div>
|
|
|
|
<h2 class="app-title">{{ $title }}</h2>
|
|
<p class="app-message">{{ $message }}</p>
|
|
|
|
@if(!empty($settings['maintenance_mode_end_at']))
|
|
<div class="countdown-wrapper" id="timer">
|
|
<div class="countdown-box">
|
|
<span class="cd-val" id="days">00</span>
|
|
<span class="cd-label">Days</span>
|
|
</div>
|
|
<div class="countdown-box">
|
|
<span class="cd-val" id="hours">00</span>
|
|
<span class="cd-label">Hours</span>
|
|
</div>
|
|
<div class="countdown-box">
|
|
<span class="cd-val" id="minutes">00</span>
|
|
<span class="cd-label">Mins</span>
|
|
</div>
|
|
<div class="countdown-box">
|
|
<span class="cd-val" id="seconds">00</span>
|
|
<span class="cd-label">Secs</span>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function () {
|
|
const targetDate = new Date("{{ $settings['maintenance_mode_end_at'] }}").getTime();
|
|
const updateCountdown = () => {
|
|
const now = new Date().getTime();
|
|
const distance = targetDate - now;
|
|
|
|
if (distance < 0) {
|
|
document.getElementById("days").innerText = "00";
|
|
document.getElementById("hours").innerText = "00";
|
|
document.getElementById("minutes").innerText = "00";
|
|
document.getElementById("seconds").innerText = "00";
|
|
return;
|
|
}
|
|
|
|
const d = Math.floor(distance / (1000 * 60 * 60 * 24));
|
|
const h = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
|
const m = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
|
const s = Math.floor((distance % (1000 * 60)) / 1000);
|
|
|
|
document.getElementById("days").innerText = d.toString().padStart(2, '0');
|
|
document.getElementById("hours").innerText = h.toString().padStart(2, '0');
|
|
document.getElementById("minutes").innerText = m.toString().padStart(2, '0');
|
|
document.getElementById("seconds").innerText = s.toString().padStart(2, '0');
|
|
};
|
|
setInterval(updateCountdown, 1000);
|
|
updateCountdown();
|
|
})();
|
|
</script>
|
|
@endif
|
|
|
|
<div style="margin-top: 60px; font-size: 0.8rem; color: #bbb;">
|
|
© {{ date('Y') }} {{ $settings['app_name'] ?? config('app.name') }}
|
|
</div>
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html> |