File: /home/muratemr/theotto.tr/admin/login.php
<?php
/**
* admin/login.php
*/
declare(strict_types=1);
require_once __DIR__ . '/../includes/db.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/functions.php';
// Zaten giriş yapmışsa dashboard'a yönlendir
if (is_logged_in()) {
header('Location: dashboard.php');
exit;
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = post_str('username');
$password = post_str('password');
$ip = $_SERVER['HTTP_CF_CONNECTING_IP']
?? $_SERVER['HTTP_X_FORWARDED_FOR']
?? $_SERVER['REMOTE_ADDR']
?? '0.0.0.0';
if ($username === '' || $password === '') {
$error = 'Kullanıcı adı ve şifre zorunludur.';
} else {
$result = attempt_login($username, $password, $ip);
if ($result['success']) {
header('Location: dashboard.php');
exit;
}
$error = $result['message'];
}
}
$restaurant_name = get_setting('restaurant_name', 'Restoran');
?>
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Giriş · <?= e($restaurant_name) ?></title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,600;1,400&family=DM+Sans:wght@300;400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--gold: #c8a96e;
--gold-dim: #9a7d4a;
--bg: #0c0c0e;
--panel: #111115;
--border: rgba(200,169,110,.14);
--border-focus: rgba(200,169,110,.5);
--text: #e8e0d0;
--muted: #5a5550;
--error-bg: rgba(180,50,50,.12);
--error-border:rgba(180,50,50,.4);
--error-text: #e07070;
--ff-display: 'Cormorant Garamond', Georgia, serif;
--ff-body: 'DM Sans', system-ui, sans-serif;
--radius: 2px;
--transition: .22s ease;
}
html, body {
height: 100%;
background: var(--bg);
font-family: var(--ff-body);
font-weight: 300;
color: var(--text);
-webkit-font-smoothing: antialiased;
}
/* ── LAYOUT ────────────────────────────── */
.login-wrap {
min-height: 100vh;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr auto;
}
@media (min-width: 960px) {
.login-wrap {
grid-template-columns: 1fr 480px;
grid-template-rows: 1fr;
}
}
/* ── LEFT PANEL (decorative) ───────────── */
.login-deco {
display: none;
position: relative;
overflow: hidden;
background: #0e0e10;
border-right: 1px solid var(--border);
}
@media (min-width: 960px) { .login-deco { display: block; } }
.deco-inner {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 3rem;
text-align: center;
}
/* Geometric background */
.deco-bg {
position: absolute;
inset: 0;
overflow: hidden;
}
.deco-bg::before {
content: '';
position: absolute;
top: -20%;
left: -20%;
width: 140%;
height: 140%;
background:
radial-gradient(ellipse 55% 45% at 35% 40%, rgba(200,169,110,.06) 0%, transparent 60%),
radial-gradient(ellipse 40% 60% at 75% 70%, rgba(200,169,110,.04) 0%, transparent 60%);
}
.deco-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(200,169,110,.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(200,169,110,.04) 1px, transparent 1px);
background-size: 48px 48px;
}
.deco-circle {
position: absolute;
border: 1px solid rgba(200,169,110,.07);
border-radius: 50%;
}
.deco-circle:nth-child(1) { width: 520px; height: 520px; top: 50%; left: 50%; transform: translate(-50%,-50%); }
.deco-circle:nth-child(2) { width: 360px; height: 360px; top: 50%; left: 50%; transform: translate(-50%,-50%); }
.deco-circle:nth-child(3) { width: 200px; height: 200px; top: 50%; left: 50%; transform: translate(-50%,-50%); }
/* Deco content */
.deco-name {
font-family: var(--ff-display);
font-size: clamp(2.4rem, 4vw, 3.8rem);
font-weight: 400;
color: #e8dfc8;
letter-spacing: .04em;
line-height: 1.1;
position: relative;
z-index: 1;
animation: fadeUp .9s .1s both;
}
.deco-name em {
display: block;
font-style: italic;
color: var(--gold);
font-size: .7em;
letter-spacing: .12em;
margin-bottom: .4rem;
font-weight: 400;
}
.deco-divider {
width: 48px;
height: 1px;
background: var(--gold);
margin: 1.6rem auto;
position: relative;
z-index: 1;
animation: fadeUp .9s .25s both;
}
.deco-tagline {
font-size: .78rem;
letter-spacing: .22em;
text-transform: uppercase;
color: var(--muted);
position: relative;
z-index: 1;
animation: fadeUp .9s .4s both;
}
/* ── RIGHT PANEL (form) ────────────────── */
.login-form-wrap {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: clamp(2rem, 8vw, 4rem) clamp(1.5rem, 6vw, 3.5rem);
background: var(--panel);
min-height: 100vh;
}
@media (min-width: 960px) { .login-form-wrap { min-height: unset; } }
.form-container {
width: 100%;
max-width: 380px;
animation: fadeUp .7s .15s both;
}
/* Mobile: restoran adı */
.mobile-brand {
text-align: center;
margin-bottom: 2.8rem;
display: block;
}
@media (min-width: 960px) { .mobile-brand { display: none; } }
.mobile-brand-name {
font-family: var(--ff-display);
font-size: 2rem;
color: #e8dfc8;
letter-spacing: .05em;
display: block;
margin-bottom: .2rem;
}
.mobile-brand-sub {
font-size: .72rem;
letter-spacing: .3em;
text-transform: uppercase;
color: var(--muted);
}
/* Heading */
.form-heading {
margin-bottom: 2.2rem;
}
.form-heading h1 {
font-family: var(--ff-display);
font-size: 1.9rem;
font-weight: 600;
color: #e8dfc8;
letter-spacing: .02em;
line-height: 1.1;
margin-bottom: .4rem;
}
.form-heading p {
font-size: .8rem;
color: var(--muted);
letter-spacing: .06em;
}
/* Fields */
.field-group {
margin-bottom: 1.3rem;
}
.field-label {
display: block;
font-size: .72rem;
letter-spacing: .18em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: .55rem;
transition: color var(--transition);
}
.field-wrap {
position: relative;
display: flex;
align-items: center;
border: 1px solid var(--border);
background: rgba(255,255,255,.02);
transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
border-radius: var(--radius);
}
.field-wrap:focus-within {
border-color: var(--border-focus);
background: rgba(200,169,110,.03);
box-shadow: 0 0 0 3px rgba(200,169,110,.07);
}
.field-wrap:focus-within + .field-label,
.field-group:focus-within .field-label {
color: var(--gold-dim);
}
.field-icon {
width: 44px;
display: flex;
align-items: center;
justify-content: center;
color: var(--muted);
font-size: .9rem;
flex-shrink: 0;
transition: color var(--transition);
}
.field-wrap:focus-within .field-icon { color: var(--gold-dim); }
.field-input {
flex: 1;
background: transparent;
border: none;
outline: none;
color: var(--text);
font-family: var(--ff-body);
font-size: .9rem;
font-weight: 400;
padding: .85rem .85rem .85rem 0;
min-width: 0;
}
.field-input::placeholder { color: #3a3830; }
.field-input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 100px #111115 inset;
-webkit-text-fill-color: var(--text);
}
.toggle-pass {
width: 44px;
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
cursor: pointer;
color: var(--muted);
font-size: .9rem;
flex-shrink: 0;
transition: color var(--transition);
padding: 0;
}
.toggle-pass:hover { color: var(--gold); }
/* Error */
.error-msg {
display: flex;
align-items: center;
gap: .55rem;
background: var(--error-bg);
border: 1px solid var(--error-border);
color: var(--error-text);
font-size: .8rem;
padding: .75rem 1rem;
margin-bottom: 1.6rem;
border-radius: var(--radius);
animation: shakeX .4s ease;
}
.error-msg i { font-size: .95rem; flex-shrink: 0; }
/* Submit button */
.btn-submit {
width: 100%;
background: var(--gold);
color: #0c0c0e;
border: none;
padding: .95rem 1.5rem;
font-family: var(--ff-body);
font-size: .8rem;
font-weight: 500;
letter-spacing: .2em;
text-transform: uppercase;
cursor: pointer;
border-radius: var(--radius);
display: flex;
align-items: center;
justify-content: center;
gap: .6rem;
transition: background var(--transition), transform .15s, box-shadow var(--transition);
margin-top: 1.8rem;
position: relative;
overflow: hidden;
}
.btn-submit::after {
content: '';
position: absolute;
inset: 0;
background: rgba(255,255,255,0);
transition: background .2s;
}
.btn-submit:hover { background: #d9bb82; transform: translateY(-1px); box-shadow: 0 8px 24px rgba(200,169,110,.2); }
.btn-submit:hover::after { background: rgba(255,255,255,.05); }
.btn-submit:active { transform: translateY(0); }
.btn-submit:disabled { opacity: .5; cursor: not-allowed; transform: none; }
/* Footer note */
.form-foot {
margin-top: 1.6rem;
text-align: center;
font-size: .73rem;
color: var(--muted);
letter-spacing: .05em;
}
.form-foot a {
color: var(--gold-dim);
text-decoration: none;
transition: color var(--transition);
}
.form-foot a:hover { color: var(--gold); }
/* Page footer */
.page-foot {
text-align: center;
font-size: .68rem;
color: #2e2c28;
padding: 1.4rem;
letter-spacing: .05em;
}
@media (min-width: 960px) { .page-foot { display: none; } }
/* ── ANIMATIONS ────────────────────────── */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(18px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes shakeX {
0%,100% { transform: translateX(0); }
20% { transform: translateX(-6px); }
40% { transform: translateX(6px); }
60% { transform: translateX(-4px); }
80% { transform: translateX(4px); }
}
/* ── LOADING SPINNER (submit) ──────────── */
.spinner {
width: 14px; height: 14px;
border: 2px solid rgba(12,12,14,.3);
border-top-color: #0c0c0e;
border-radius: 50%;
animation: spin .6s linear infinite;
display: none;
}
@keyframes spin { to { transform: rotate(360deg); } }
</style>
</head>
<body>
<div class="login-wrap">
<!-- ── Dekoratif sol panel (masaüstü) ── -->
<div class="login-deco">
<div class="deco-bg">
<div class="deco-grid"></div>
<div class="deco-circle"></div>
<div class="deco-circle"></div>
<div class="deco-circle"></div>
</div>
<div class="deco-inner">
<div class="deco-name">
<em>Yönetim Paneli</em>
<?= e($restaurant_name) ?>
</div>
<div class="deco-divider"></div>
<div class="deco-tagline">Güvenli erişim · Tam kontrol</div>
</div>
</div>
<!-- ── Form paneli ── -->
<div class="login-form-wrap">
<div class="form-container">
<!-- Mobil marka -->
<span class="mobile-brand">
<span class="mobile-brand-name"><?= e($restaurant_name) ?></span>
<span class="mobile-brand-sub">Yönetim Paneli</span>
</span>
<!-- Başlık -->
<div class="form-heading">
<h1>Hoş geldiniz</h1>
<p>Devam etmek için giriş yapın</p>
</div>
<!-- Hata mesajı -->
<?php if ($error): ?>
<div class="error-msg">
<i class="bi bi-exclamation-circle-fill"></i>
<?= e($error) ?>
</div>
<?php endif; ?>
<!-- Form -->
<form method="POST" autocomplete="on" id="loginForm" novalidate>
<div class="field-group">
<label class="field-label" for="username">Kullanıcı Adı</label>
<div class="field-wrap">
<span class="field-icon"><i class="bi bi-person"></i></span>
<input
type="text"
name="username"
id="username"
class="field-input"
value="<?= e(post_str('username')) ?>"
placeholder="kullanici_adi"
autocomplete="username"
autofocus
required>
</div>
</div>
<div class="field-group">
<label class="field-label" for="passwordField">Şifre</label>
<div class="field-wrap">
<span class="field-icon"><i class="bi bi-lock"></i></span>
<input
type="password"
name="password"
id="passwordField"
class="field-input"
placeholder="••••••••"
autocomplete="current-password"
required>
<button type="button" class="toggle-pass" id="togglePassword" title="Şifreyi göster/gizle" aria-label="Şifreyi göster">
<i class="bi bi-eye" id="eyeIcon"></i>
</button>
</div>
</div>
<button type="submit" class="btn-submit" id="submitBtn">
<span class="spinner" id="btnSpinner"></span>
<i class="bi bi-box-arrow-in-right" id="btnIcon"></i>
<span id="btnText">Giriş Yap</span>
</button>
</form>
<div class="form-foot">
<script>
/* Şifre göster/gizle */
document.getElementById('togglePassword').addEventListener('click', function () {
const field = document.getElementById('passwordField');
const icon = document.getElementById('eyeIcon');
const isPass = field.type === 'password';
field.type = isPass ? 'text' : 'password';
icon.className = isPass ? 'bi bi-eye-slash' : 'bi bi-eye';
this.setAttribute('aria-label', isPass ? 'Şifreyi gizle' : 'Şifreyi göster');
});
/* Submit loading state */
document.getElementById('loginForm').addEventListener('submit', function () {
const btn = document.getElementById('submitBtn');
btn.disabled = true;
document.getElementById('btnSpinner').style.display = 'block';
document.getElementById('btnIcon').style.display = 'none';
document.getElementById('btnText').textContent = 'Giriş yapılıyor…';
});
/* Demo doldur */
document.getElementById('username').value = 'admin';
document.getElementById('passwordField').focus();
}
/* Enter ile submit */
document.addEventListener('keydown', function (e) {
if (e.key === 'Enter' && document.activeElement.tagName !== 'BUTTON') {
document.getElementById('loginForm').requestSubmit();
}
});
</script>
</body>
</html>