461 lines
27 KiB
PHP
461 lines
27 KiB
PHP
<?php
|
||
require_once 'db/config.php';
|
||
$project_name = $_SERVER['PROJECT_NAME'] ?? 'Nano Media AI';
|
||
$project_description = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Generate unique AI photos and high-quality stock videos.';
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title><?php echo htmlspecialchars($project_name); ?></title>
|
||
<meta name="description" content="<?php echo htmlspecialchars($project_description); ?>">
|
||
|
||
<!-- Bootstrap 5 CSS -->
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||
<!-- Google Fonts: Inter & Montserrat -->
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Montserrat:wght@800&display=swap" rel="stylesheet">
|
||
<!-- Font Awesome -->
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||
|
||
<!-- Editor Libraries -->
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.css">
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
|
||
|
||
<!-- Custom CSS -->
|
||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||
<style>
|
||
:root {
|
||
--nano-yellow: #FFDE59;
|
||
--nano-black: #1A1A1A;
|
||
--nano-white: #FFFFFF;
|
||
--nano-gray: #F5F5F5;
|
||
--nano-radius: 24px;
|
||
}
|
||
body {
|
||
background-color: var(--nano-gray);
|
||
font-family: 'Inter', sans-serif;
|
||
}
|
||
.navbar {
|
||
background-color: var(--nano-white) !important;
|
||
border-bottom: 2px solid var(--nano-black);
|
||
padding: 15px 0;
|
||
}
|
||
.navbar-brand {
|
||
font-family: 'Montserrat', sans-serif;
|
||
color: var(--nano-black) !important;
|
||
font-size: 1.5rem;
|
||
text-transform: uppercase;
|
||
}
|
||
.btn-nano {
|
||
background-color: var(--nano-yellow);
|
||
color: var(--nano-black);
|
||
border: 2px solid var(--nano-black);
|
||
border-radius: var(--nano-radius);
|
||
font-weight: 700;
|
||
padding: 10px 25px;
|
||
transition: all 0.2s ease;
|
||
}
|
||
.btn-nano:hover {
|
||
background-color: var(--nano-black);
|
||
color: var(--nano-yellow);
|
||
transform: translateY(-2px);
|
||
}
|
||
.card-nano {
|
||
background: var(--nano-white);
|
||
border: 2px solid var(--nano-black);
|
||
border-radius: var(--nano-radius);
|
||
box-shadow: 8px 8px 0px var(--nano-black);
|
||
overflow: hidden;
|
||
}
|
||
.form-control-nano {
|
||
border: 2px solid var(--nano-black);
|
||
border-radius: 15px;
|
||
padding: 12px;
|
||
font-weight: 500;
|
||
}
|
||
.form-control-nano:focus {
|
||
box-shadow: none;
|
||
border-color: var(--nano-yellow);
|
||
background-color: #fffde7;
|
||
}
|
||
.badge-nano {
|
||
background: var(--nano-yellow);
|
||
color: var(--nano-black);
|
||
border: 1px solid var(--nano-black);
|
||
border-radius: 10px;
|
||
padding: 5px 12px;
|
||
font-weight: 600;
|
||
}
|
||
.editor-preview-container {
|
||
background: #eee;
|
||
border: 2px solid var(--nano-black);
|
||
border-radius: var(--nano-radius);
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
.canvas-container {
|
||
margin: 0 auto;
|
||
}
|
||
.sticker-item {
|
||
cursor: pointer;
|
||
transition: transform 0.2s;
|
||
border: 2px solid transparent;
|
||
border-radius: 10px;
|
||
padding: 5px;
|
||
font-size: 2rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 50px;
|
||
height: 50px;
|
||
}
|
||
.sticker-item:hover {
|
||
transform: scale(1.1);
|
||
border-color: var(--nano-yellow);
|
||
}
|
||
.tool-btn {
|
||
border: 2px solid var(--nano-black);
|
||
border-radius: 12px;
|
||
padding: 8px;
|
||
background: white;
|
||
transition: all 0.2s;
|
||
}
|
||
.tool-btn:hover, .tool-btn.active {
|
||
background: var(--nano-yellow);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<nav class="navbar navbar-expand-lg sticky-top">
|
||
<div class="container">
|
||
<a class="navbar-brand fw-bold" href="/">
|
||
<i class="fas fa-banana text-warning me-2"></i><?php echo htmlspecialchars($project_name); ?>
|
||
</a>
|
||
<div class="ms-auto d-flex align-items-center">
|
||
<a href="#history" class="btn btn-nano btn-sm">История</a>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<main class="container py-5">
|
||
<!-- Hero -->
|
||
<div class="text-center mb-5">
|
||
<h1 class="display-4 fw-black mb-3" style="font-family: 'Montserrat', sans-serif;">NANO GENERATOR 🍌</h1>
|
||
<p class="lead text-dark fw-medium">Создавай крутые ИИ фото и качественные сток-видео.</p>
|
||
</div>
|
||
|
||
<!-- Generator Section -->
|
||
<section class="row justify-content-center mb-5">
|
||
<div class="col-lg-12">
|
||
<div class="card-nano p-4">
|
||
<form id="generation-form">
|
||
<div class="row g-3">
|
||
<div class="col-md-2">
|
||
<label class="form-label small fw-bold">ТИП КОНТЕНТА</label>
|
||
<select class="form-select form-control-nano" id="media-type" name="type">
|
||
<option value="photo">ФОТО (ИИ)</option>
|
||
<option value="video">ВИДЕО (STOCK)</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-md-2">
|
||
<label class="form-label small fw-bold">СТИЛЬ</label>
|
||
<select class="form-select form-control-nano" id="style" name="style">
|
||
<option value="">ОРИГИНАЛ</option>
|
||
<option value="anime">АНИМЕ</option>
|
||
<option value="cyberpunk">КИБЕРПАНК</option>
|
||
<option value="3d-render">3D SOFT</option>
|
||
<option value="minimalism">МИНИМАЛИЗМ</option>
|
||
<option value="cinematic">КИНО</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<label class="form-label small fw-bold">ТВОЙ ЗАПРОС</label>
|
||
<input type="text" class="form-control form-control-nano" id="prompt" name="prompt" placeholder="Что нарисуем или найдем?.." required>
|
||
</div>
|
||
<div class="col-md-2 d-flex align-items-end">
|
||
<button type="submit" class="btn btn-nano w-100" id="generate-btn">
|
||
СОЗДАТЬ
|
||
</button>
|
||
</div>
|
||
<div class="col-md-2 d-flex align-items-end">
|
||
<input type="file" id="upload-image" accept="image/*" class="d-none">
|
||
<button type="button" class="btn btn-outline-dark w-100 rounded-pill py-2" onclick="document.getElementById('upload-image').click()">
|
||
<i class="fas fa-upload me-1"></i> СВОЁ ФОТО
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
|
||
<div id="result-preview" class="mt-4 position-relative" style="min-height: 400px; background: #fafafa; border: 2px dashed #ccc; border-radius: 20px; display: flex; align-items: center; justify-content: center;">
|
||
<div class="text-center text-muted" id="placeholder-text">
|
||
<i class="fas fa-image fa-3x mb-3"></i>
|
||
<p class="fw-bold">ТУТ БУДЕТ МАГИЯ</p>
|
||
</div>
|
||
|
||
<div class="loading-spinner text-center d-none" id="loading-state">
|
||
<div class="spinner-border text-dark" role="status"></div>
|
||
<p class="mt-3 fw-bold">ГОТОВИМ БАНАНЫ...</p>
|
||
</div>
|
||
|
||
<div id="content-container" class="d-none w-100 h-100 p-2 text-center"></div>
|
||
|
||
<div id="info-overlay" class="position-absolute top-0 start-0 p-3 d-none">
|
||
<span class="badge-nano" id="provider-badge"></span>
|
||
</div>
|
||
|
||
<div id="action-buttons" class="position-absolute bottom-0 end-0 p-3 d-none d-flex gap-2">
|
||
<button class="btn btn-nano btn-sm" id="edit-btn">
|
||
<i class="fas fa-wand-magic-sparkles"></i> EDIT
|
||
</button>
|
||
<button class="btn btn-dark btn-sm rounded-pill" id="download-btn">
|
||
<i class="fas fa-download"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="status-message" class="mt-3 alert alert-warning border-2 border-dark d-none" role="alert"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- History -->
|
||
<section id="history" class="py-5">
|
||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||
<h2 class="fw-black mb-0" style="font-family: 'Montserrat', sans-serif;">ГАЛЕРЕЯ 📂</h2>
|
||
<button class="btn btn-outline-dark btn-sm rounded-pill" onclick="location.reload()"><i class="fas fa-sync"></i> Обновить</button>
|
||
</div>
|
||
<div class="row g-4" id="history-grid">
|
||
<?php
|
||
try {
|
||
$stmt = db()->query("SELECT * FROM media_history ORDER BY created_at DESC LIMIT 12");
|
||
$history = $stmt->fetchAll();
|
||
foreach ($history as $item):
|
||
?>
|
||
<div class="col-md-4 col-sm-6">
|
||
<div class="card-nano h-100 history-card">
|
||
<?php if ($item['type'] === 'photo'): ?>
|
||
<img src="<?php echo htmlspecialchars($item['result_url']); ?>" class="w-100" style="height: 250px; object-fit: cover; border-bottom: 2px solid #000;">
|
||
<?php else: ?>
|
||
<div class="bg-dark" style="height: 250px; border-bottom: 2px solid #000; position: relative;">
|
||
<video class="w-100 h-100" style="object-fit: cover;" muted onmouseover="this.play()" onmouseout="this.pause()">
|
||
<source src="<?php echo htmlspecialchars($item['result_url']); ?>" type="video/mp4">
|
||
</video>
|
||
<div class="position-absolute top-50 start-50 translate-middle pointer-events-none">
|
||
<i class="fas fa-play text-white fa-2x opacity-50"></i>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<div class="p-3">
|
||
<p class="small fw-bold text-truncate mb-2 history-prompt"><?php echo htmlspecialchars($item['prompt']); ?></p>
|
||
<div class="d-flex justify-content-between align-items-center">
|
||
<span class="badge-nano py-1 px-2" style="font-size: 0.7rem;"><?php echo strtoupper($item['type']); ?></span>
|
||
<div class="d-flex gap-2">
|
||
<?php if ($item['type'] === 'photo'): ?>
|
||
<button class="btn btn-sm btn-outline-dark rounded-pill history-edit-btn" data-url="<?php echo htmlspecialchars($item['result_url']); ?>">
|
||
<i class="fas fa-magic"></i>
|
||
</button>
|
||
<?php endif; ?>
|
||
<a href="<?php echo htmlspecialchars($item['result_url']); ?>" download class="btn btn-sm btn-dark rounded-pill">
|
||
<i class="fas fa-download"></i>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; } catch (Exception $e) {} ?>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Nano Editor Modal -->
|
||
<div class="modal fade" id="editorModal" data-bs-backdrop="static" tabindex="-1">
|
||
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||
<div class="modal-content card-nano border-0">
|
||
<div class="modal-header border-bottom border-2 border-dark bg-yellow-soft">
|
||
<h5 class="modal-title fw-black"><i class="fas fa-banana text-warning"></i> NANO EDITOR AI PRO</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||
</div>
|
||
<div class="modal-body p-0">
|
||
<div class="row g-0">
|
||
<div class="col-lg-8 bg-light p-3 border-end border-2 border-dark d-flex flex-column">
|
||
<div class="editor-preview-container d-flex align-items-center justify-content-center flex-grow-1" style="min-height: 500px;">
|
||
<div id="fabric-wrapper">
|
||
<canvas id="editor-canvas"></canvas>
|
||
</div>
|
||
<img id="cropper-image" src="" style="display: none; max-width: 100%;">
|
||
|
||
<div id="editor-loading" class="position-absolute top-0 start-0 w-100 h-100 d-none flex-column align-items-center justify-content-center" style="background: rgba(255,255,255,0.8); z-index: 10;">
|
||
<div class="spinner-border text-dark"></div>
|
||
<span class="fw-bold mt-2">МАГИЯ В ПРОЦЕССЕ...</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Transform Controls (Quick Access) -->
|
||
<div id="transform-bar" class="mt-3 p-2 bg-white rounded-3 border border-2 border-dark d-flex justify-content-center gap-3 d-none">
|
||
<button class="btn btn-sm tool-btn" onclick="rotateLeft()"><i class="fas fa-undo"></i> -90°</button>
|
||
<button class="btn btn-sm tool-btn" onclick="rotateRight()"><i class="fas fa-redo"></i> +90°</button>
|
||
<button class="btn btn-sm tool-btn" onclick="flipH()"><i class="fas fa-arrows-alt-h"></i> Flip H</button>
|
||
<button class="btn btn-sm tool-btn" onclick="flipV()"><i class="fas fa-arrows-alt-v"></i> Flip V</button>
|
||
<button class="btn btn-sm btn-dark rounded-pill px-3" id="apply-crop-btn">APPLY CROP</button>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-4 p-4 overflow-auto" style="max-height: 80vh;">
|
||
<ul class="nav nav-tabs border-0 mb-3 flex-nowrap overflow-auto" id="editor-tabs">
|
||
<li class="nav-item"><button class="nav-link active fw-bold text-dark border-0 small" data-bs-toggle="tab" data-bs-target="#filters-panel">ФИЛЬТРЫ</button></li>
|
||
<li class="nav-item"><button class="nav-link fw-bold text-dark border-0 small" data-bs-toggle="tab" data-bs-target="#transform-panel">ТРАНСФОРМ</button></li>
|
||
<li class="nav-item"><button class="nav-link fw-bold text-dark border-0 small" data-bs-toggle="tab" data-bs-target="#decor-panel">ДЕКОР</button></li>
|
||
<li class="nav-item"><button class="nav-link fw-bold text-dark border-0 small" data-bs-toggle="tab" data-bs-target="#ai-magic-panel">AI MAGIC</button></li>
|
||
</ul>
|
||
<div class="tab-content pt-2">
|
||
<!-- Filters -->
|
||
<div class="tab-pane fade show active" id="filters-panel">
|
||
<?php
|
||
$filters = [
|
||
'brightness' => ['label' => 'Яркость', 'min' => 0, 'max' => 200, 'val' => 100],
|
||
'contrast' => ['label' => 'Контраст', 'min' => 0, 'max' => 200, 'val' => 100],
|
||
'saturate' => ['label' => 'Насыщенность', 'min' => 0, 'max' => 200, 'val' => 100],
|
||
'blur' => ['label' => 'Размытие', 'min' => 0, 'max' => 20, 'val' => 0],
|
||
'hue-rotate' => ['label' => 'Оттенок', 'min' => 0, 'max' => 360, 'val' => 0],
|
||
'sepia' => ['label' => 'Сепия', 'min' => 0, 'max' => 100, 'val' => 0],
|
||
'grayscale' => ['label' => 'Ч/Б', 'min' => 0, 'max' => 100, 'val' => 0],
|
||
'vignette' => ['label' => 'Виньетка', 'min' => 0, 'max' => 100, 'val' => 0],
|
||
'noise' => ['label' => 'Шум', 'min' => 0, 'max' => 100, 'val' => 0]
|
||
];
|
||
foreach ($filters as $id => $f): ?>
|
||
<div class="mb-3">
|
||
<div class="d-flex justify-content-between">
|
||
<label class="form-label small fw-bold"><?php echo $f['label']; ?></label>
|
||
<span class="small fw-bold text-muted" id="val-<?php echo $id; ?>"><?php echo $f['val']; ?></span>
|
||
</div>
|
||
<input type="range" class="form-range filter-range" data-filter="<?php echo $id; ?>" min="<?php echo $f['min']; ?>" max="<?php echo $f['max']; ?>" value="<?php echo $f['val']; ?>">
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
|
||
<!-- Transform -->
|
||
<div class="tab-pane fade" id="transform-panel">
|
||
<div class="d-grid gap-3">
|
||
<button class="btn btn-nano w-100" id="start-crop-btn">
|
||
<i class="fas fa-crop-alt"></i> ИНСТРУМЕНТ ОБРЕЗКИ
|
||
</button>
|
||
<div class="row g-2">
|
||
<div class="col-6">
|
||
<button class="btn btn-outline-dark w-100 py-3" onclick="rotateLeft()">
|
||
<i class="fas fa-undo d-block mb-1"></i> -90°
|
||
</button>
|
||
</div>
|
||
<div class="col-6">
|
||
<button class="btn btn-outline-dark w-100 py-3" onclick="rotateRight()">
|
||
<i class="fas fa-redo d-block mb-1"></i> +90°
|
||
</button>
|
||
</div>
|
||
<div class="col-6">
|
||
<button class="btn btn-outline-dark w-100 py-3" onclick="flipH()">
|
||
<i class="fas fa-arrows-alt-h d-block mb-1"></i> Flip H
|
||
</button>
|
||
</div>
|
||
<div class="col-6">
|
||
<button class="btn btn-outline-dark w-100 py-3" onclick="flipV()">
|
||
<i class="fas fa-arrows-alt-v d-block mb-1"></i> Flip V
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Decor -->
|
||
<div class="tab-pane fade" id="decor-panel">
|
||
<div class="mb-4">
|
||
<label class="form-label small fw-bold">РИСОВАНИЕ КИСТЬЮ</label>
|
||
<div class="d-flex gap-2 mb-2">
|
||
<button class="btn tool-btn flex-grow-1" id="brush-toggle"><i class="fas fa-paint-brush"></i> Кисть</button>
|
||
<input type="color" class="form-control form-control-color border-2 border-dark" id="brush-color" value="#FFDE59" title="Цвет кисти">
|
||
</div>
|
||
<input type="range" class="form-range" id="brush-size" min="1" max="100" value="10">
|
||
</div>
|
||
|
||
<div class="mb-4">
|
||
<label class="form-label small fw-bold">ТЕКСТ</label>
|
||
<div class="input-group mb-2">
|
||
<input type="text" id="text-input" class="form-control form-control-nano" placeholder="Ваш текст...">
|
||
<button class="btn btn-dark" id="add-text-btn"><i class="fas fa-plus"></i></button>
|
||
</div>
|
||
<div class="d-flex gap-2">
|
||
<select id="font-family" class="form-select form-control-nano py-1">
|
||
<option value="Montserrat">Montserrat</option>
|
||
<option value="Inter">Inter</option>
|
||
<option value="Arial">Arial</option>
|
||
<option value="Courier New">Monospace</option>
|
||
</select>
|
||
<input type="color" class="form-control form-control-color border-2 border-dark" id="text-color" value="#000000">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-4">
|
||
<label class="form-label small fw-bold">СЛОИ (OBJECTS)</label>
|
||
<div class="d-flex gap-2">
|
||
<button class="btn btn-outline-dark btn-sm flex-grow-1" onclick="bringToFront()"><i class="fas fa-layer-group"></i> Вперёд</button>
|
||
<button class="btn btn-outline-dark btn-sm flex-grow-1" onclick="sendToBack()"><i class="fas fa-level-down-alt"></i> Назад</button>
|
||
<button class="btn btn-outline-danger btn-sm" onclick="deleteObject()"><i class="fas fa-trash"></i></button>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<label class="form-label small fw-bold">СТИКЕРЫ 🍌✨</label>
|
||
<div class="d-flex flex-wrap gap-2 p-2 bg-white rounded-3 border border-2 border-dark">
|
||
<div class="sticker-item" data-sticker="🍌">🍌</div>
|
||
<div class="sticker-item" data-sticker="🐒">🐒</div>
|
||
<div class="sticker-item" data-sticker="🌴">🌴</div>
|
||
<div class="sticker-item" data-sticker="🕶️">🕶️</div>
|
||
<div class="sticker-item" data-sticker="🔥">🔥</div>
|
||
<div class="sticker-item" data-sticker="❤️">❤️</div>
|
||
<div class="sticker-item" data-sticker="✨">✨</div>
|
||
<div class="sticker-item" data-sticker="🚀">🚀</div>
|
||
<div class="sticker-item" data-sticker="🎨">🎨</div>
|
||
<div class="sticker-item" data-sticker="⭐">⭐</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- AI Magic -->
|
||
<div class="tab-pane fade" id="ai-magic-panel">
|
||
<div class="p-3 bg-yellow-soft rounded-4 border border-2 border-dark mb-3">
|
||
<label class="form-label small fw-bold">ЧТО ДОРИСОВАТЬ?</label>
|
||
<textarea class="form-control form-control-nano mb-2" id="ai-edit-prompt" rows="3" placeholder="Напр: Добавь солнечные очки..."></textarea>
|
||
<button class="btn btn-nano w-100" id="apply-ai-magic">ПРИМЕНИТЬ МАГИЮ</button>
|
||
</div>
|
||
<div class="d-grid gap-2">
|
||
<button class="btn btn-outline-dark btn-sm rounded-pill" id="remove-bg-btn"><i class="fas fa-user-slash me-1"></i> Удалить фон</button>
|
||
<button class="btn btn-outline-dark btn-sm rounded-pill" id="upscale-btn"><i class="fas fa-expand-arrows-alt me-1"></i> Улучшить (HD)</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<hr class="border-2 border-dark">
|
||
<div class="d-grid gap-2">
|
||
<button class="btn btn-outline-danger btn-sm rounded-pill" id="reset-editor"><i class="fas fa-undo"></i> СБРОСИТЬ ВСЁ</button>
|
||
<button class="btn btn-nano w-100 py-3 mt-2" id="save-edited-btn">
|
||
<i class="fas fa-download me-2"></i> СКАЧАТЬ PNG
|
||
</button>
|
||
<button class="btn btn-dark w-100 py-2 rounded-pill" id="save-to-gallery-btn">
|
||
<i class="fas fa-cloud-upload-alt me-2"></i> СОХРАНИТЬ В ГАЛЕРЕЮ
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<footer class="py-5 text-center">
|
||
<p class="small fw-bold">© <?php echo date('Y'); ?> <?php echo htmlspecialchars($project_name); ?> 🍌</p>
|
||
</footer>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||
</body>
|
||
</html>
|