Compare commits
No commits in common. "ai-dev" and "master" have entirely different histories.
187
admin.php
187
admin.php
@ -1,187 +0,0 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Hardcoded credentials
|
||||
$valid_username = 'admin';
|
||||
$valid_password = 'password';
|
||||
|
||||
$is_logged_in = isset($_SESSION['loggedin']) && $_SESSION['loggedin'] === true;
|
||||
$error_message = '';
|
||||
$pdo = db();
|
||||
$editing_fact = null;
|
||||
|
||||
// Handle Login/Logout
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['logout'])) {
|
||||
$_SESSION = [];
|
||||
session_destroy();
|
||||
header("Location: admin.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
if (isset($_POST['login'])) {
|
||||
$username = $_POST['username'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
if ($username === $valid_username && $password === $valid_password) {
|
||||
$_SESSION['loggedin'] = true;
|
||||
header("Location: admin.php");
|
||||
exit;
|
||||
} else {
|
||||
$error_message = "Invalid username or password.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If logged in, handle CRUD actions
|
||||
if ($is_logged_in && $pdo) {
|
||||
// Handle Delete
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_id'])) {
|
||||
$stmt = $pdo->prepare('DELETE FROM nokia_facts WHERE id = ?');
|
||||
$stmt->execute([$_POST['delete_id']]);
|
||||
header("Location: admin.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Handle Add/Update
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['fact_text'])) {
|
||||
$fact_text = trim($_POST['fact_text']);
|
||||
$fact_id = $_POST['fact_id'] ?? null;
|
||||
|
||||
if (!empty($fact_text)) {
|
||||
if ($fact_id) { // Update
|
||||
$stmt = $pdo->prepare('UPDATE nokia_facts SET fact = ? WHERE id = ?');
|
||||
$stmt->execute([$fact_text, $fact_id]);
|
||||
} else { // Add
|
||||
$stmt = $pdo->prepare('INSERT INTO nokia_facts (fact) VALUES (?)');
|
||||
$stmt->execute([$fact_text]);
|
||||
}
|
||||
}
|
||||
header("Location: admin.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Handle Edit - Fetch fact for form
|
||||
if (isset($_GET['edit_id'])) {
|
||||
$stmt = $pdo->prepare('SELECT id, fact FROM nokia_facts WHERE id = ?');
|
||||
$stmt->execute([$_GET['edit_id']]);
|
||||
$editing_fact = $stmt->fetch();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin - LAMP Demo</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<?php include 'navbar.php'; ?>
|
||||
|
||||
<main class="container my-5">
|
||||
<?php if (!$is_logged_in): ?>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6">
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body p-4">
|
||||
<h1 class="h3 mb-3 fw-normal text-center">Admin Login</h1>
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
<form method="POST" action="admin.php">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="username" name="username" placeholder="Username" required>
|
||||
<label for="username">Username</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="password" class="form-control" id="password" name="password" placeholder="Password" required>
|
||||
<label for="password">Password</label>
|
||||
</div>
|
||||
<button class="w-100 btn btn-lg btn-primary" type="submit" name="login">Sign in</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h2 class="h4 mb-0">Nokia Facts Management</h2>
|
||||
<form method="POST" action="admin.php" class="mb-0">
|
||||
<button type="submit" name="logout" class="btn btn-sm btn-outline-secondary">Logout <i class="bi bi-box-arrow-right"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="mb-4 p-3 border rounded bg-light">
|
||||
<h3 class="h5"><?php echo $editing_fact ? 'Edit Fact' : 'Add New Fact'; ?></h3>
|
||||
<form method="POST" action="admin.php">
|
||||
<input type="hidden" name="fact_id" value="<?php echo $editing_fact['id'] ?? ''; ?>">
|
||||
<div class="input-group">
|
||||
<textarea class="form-control" name="fact_text" rows="2" placeholder="Enter a new Nokia fact..."><?php echo htmlspecialchars($editing_fact['fact'] ?? ''); ?></textarea>
|
||||
<button class="btn btn-<?php echo $editing_fact ? 'primary' : 'success'; ?>" type="submit"><?php echo $editing_fact ? 'Update Fact' : 'Add Fact'; ?></button>
|
||||
<?php if ($editing_fact): ?>
|
||||
<a href="admin.php" class="btn btn-secondary">Cancel</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Fact</th>
|
||||
<th scope="col" class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
if ($pdo) {
|
||||
$stmt = $pdo->query('SELECT id, fact, created_at FROM nokia_facts ORDER BY id DESC');
|
||||
$facts = $stmt->fetchAll();
|
||||
foreach ($facts as $fact):
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($fact['fact']); ?></td>
|
||||
<td class="text-end">
|
||||
<a href="admin.php?edit_id=<?php echo $fact['id']; ?>" class="btn btn-sm btn-outline-primary"><i class="bi bi-pencil"></i> Edit</a>
|
||||
<form method="POST" action="admin.php" class="d-inline" onsubmit="return confirm('Are you sure you want to delete this fact?');">
|
||||
<input type="hidden" name="delete_id" value="<?php echo $fact['id']; ?>">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i> Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endforeach;
|
||||
if (empty($facts)) {
|
||||
echo "<tr><td colspan='2'>No facts found. Add one above!</td></tr>";
|
||||
}
|
||||
} else {
|
||||
echo "<tr><td colspan='2'>Database connection not available.</td></tr>";
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
|
||||
<footer class="bg-white text-center text-muted py-4 mt-5 border-top">
|
||||
<div class="container">
|
||||
<p class="mb-0">© 2025 LAMP Demo. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require_once __DIR__.'/../includes/pexels.php';
|
||||
$qs = isset($_GET['queries']) ? explode(',', $_GET['queries']) : ['vibe','code','seo'];
|
||||
$out = [];
|
||||
foreach ($qs as $q) {
|
||||
$u = 'https://api.pexels.com/v1/search?query=' . urlencode(trim($q)) . '&orientation=landscape&per_page=1&page=1';
|
||||
$d = pexels_get($u);
|
||||
if ($d && !empty($d['photos'])) {
|
||||
$p = $d['photos'][0];
|
||||
$src = $p['src']['large'] ?? null;
|
||||
$dest = __DIR__.'/../assets/images/pexels/'.$p['id'].'.jpg';
|
||||
if ($src) download_to($src, $dest);
|
||||
$out[] = [
|
||||
'src' => 'assets/images/pexels/'.$p['id'].'.jpg',
|
||||
'photographer' => $p['photographer'] ?? 'Unknown',
|
||||
'photographer_url' => $p['photographer_url'] ?? '',
|
||||
];
|
||||
} else {
|
||||
// Fallback: Picsum
|
||||
$out[] = [
|
||||
'src' => 'https://picsum.photos/seed/'.urlencode(trim($q)).'/800/600',
|
||||
'photographer' => 'Random Picsum',
|
||||
'photographer_url' => 'https://picsum.photos/'
|
||||
];
|
||||
}
|
||||
}
|
||||
echo json_encode($out);
|
||||
?>
|
||||
@ -1,36 +0,0 @@
|
||||
body {
|
||||
background-color: #F8FAFC;
|
||||
color: #0F172A;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding: 6rem 1rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #6366F1;
|
||||
border-color: #6366F1;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #4F46E5;
|
||||
border-color: #4F46E5;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.05);
|
||||
transition: box-shadow 0.3s ease-in-out, transform 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.05);
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.card img {
|
||||
aspect-ratio: 16 / 9;
|
||||
object-fit: cover;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;700&display=swap"); body { font-family: "Roboto Slab", serif; background-color: #D2B48C; color: #333; } .navbar, .card, footer { background-color: #8B4513 !important; color: white; border: 3px solid #654321; } .navbar-brand, .nav-link, h1, h2, h5, p, .card-body { color: #fff !important; } .btn-primary { background-color: #008000; color: #fff; border: 2px solid #006400; } .vibe-preview { padding: 2rem; border: 2px solid #654321; margin-top: 2rem; background-color: #F5DEB3; } .vibe-preview h2, .vibe-preview p { color: #333 !important; }
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 56 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 67 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 95 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB |
95
contact.php
95
contact.php
@ -1,95 +0,0 @@
|
||||
<?php
|
||||
$message_status = '';
|
||||
$error_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_once __DIR__ . '/mail/MailService.php';
|
||||
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$message = trim($_POST['message'] ?? '');
|
||||
|
||||
if (empty($name) || empty($email) || empty($message)) {
|
||||
$error_message = 'Please fill out all fields.';
|
||||
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$error_message = 'Please enter a valid email address.';
|
||||
} else {
|
||||
$to = getenv('MAIL_TO') ?: 'admin@example.com'; // Fallback recipient
|
||||
$subject = 'New Contact Form Message from ' . $name;
|
||||
|
||||
$res = MailService::sendContactMessage($name, $email, $message, $to, $subject);
|
||||
|
||||
if (!empty($res['success'])) {
|
||||
$message_status = 'success';
|
||||
} else {
|
||||
$error_message = 'Sorry, there was an error sending your message. Please try again later.';
|
||||
// Log the actual error: error_log("MailService Error: " . $res['error']);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Contact Us - LAMP Demo</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<?php include 'navbar.php'; ?>
|
||||
|
||||
<main class="container my-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-5">
|
||||
<h1 class="display-5 text-center mb-4">Contact Us</h1>
|
||||
<?php if ($message_status === 'success'): ?>
|
||||
<div class="alert alert-success text-center">
|
||||
<h4>Thank You!</h4>
|
||||
<p>Your message has been sent successfully. We will get back to you shortly.</p>
|
||||
<a href="index.php" class="btn btn-primary">Return Home</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger">- <?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
<p class="text-center text-muted mb-4">Have a question or feedback? Fill out the form below to get in touch with us.</p>
|
||||
<form action="contact.php" method="POST">
|
||||
<div class="form-floating mb-3">
|
||||
<input type="text" class="form-control" id="name" name="name" placeholder="Your Name" required value="<?php echo htmlspecialchars($_POST['name'] ?? ''); ?>">
|
||||
<label for="name">Your Name</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input type="email" class="form-control" id="email" name="email" placeholder="Your Email" required value="<?php echo htmlspecialchars($_POST['email'] ?? ''); ?>">
|
||||
<label for="email">Your Email</label>
|
||||
</div>
|
||||
<div class="form-floating mb-4">
|
||||
<textarea class="form-control" id="message" name="message" placeholder="Your Message" required style="height: 150px;"><?php echo htmlspecialchars($_POST['message'] ?? ''); ?></textarea>
|
||||
<label for="message">Your Message</label>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-primary btn-lg"><i class="bi bi-send-fill"></i> Send Message</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-warning text-center mt-4">This is for testing purposes only — Flatlogic does not guarantee usage of the mail server. Please set up your own SMTP in <code>.env</code> (MAIL_/SMTP_ vars).</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="bg-white text-center text-muted py-4 mt-5 border-top">
|
||||
<div class="container">
|
||||
<p class="mb-0">© <?php echo date("Y"); ?> LAMP Demo. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,47 +1,17 @@
|
||||
<?php
|
||||
// db/config.php
|
||||
|
||||
// --- Database Credentials ---
|
||||
// Note: In a real application, these should be in a .env file or other secure storage.
|
||||
// Generated by setup_mariadb_project.sh — edit as needed.
|
||||
define('DB_HOST', '127.0.0.1');
|
||||
define('DB_NAME', 'lamp_app');
|
||||
define('DB_USER', 'lamp_user');
|
||||
define('DB_PASS', 'lamp_password');
|
||||
define('DB_NAME', 'app_30855');
|
||||
define('DB_USER', 'app_30855');
|
||||
define('DB_PASS', 'eee81949-37de-47f9-a26f-14ebc8402f7f');
|
||||
|
||||
/**
|
||||
* PDO Database Connection Helper
|
||||
*
|
||||
* Establishes a persistent PDO connection or returns the existing one.
|
||||
*
|
||||
* @return PDO|null Returns a PDO instance on success or null on failure.
|
||||
*/
|
||||
function db(): ?PDO
|
||||
{
|
||||
static $pdo = null;
|
||||
|
||||
if ($pdo !== null) {
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
$dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', DB_HOST, DB_NAME);
|
||||
$options = [
|
||||
function db() {
|
||||
static $pdo;
|
||||
if (!$pdo) {
|
||||
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
PDO::ATTR_PERSISTENT => true, // Use persistent connection
|
||||
];
|
||||
|
||||
try {
|
||||
// Create a new database if it doesn't exist
|
||||
$tempPdo = new PDO(sprintf('mysql:host=%s;charset=utf8mb4', DB_HOST), DB_USER, DB_PASS, $options);
|
||||
$tempPdo->exec("CREATE DATABASE IF NOT EXISTS " . DB_NAME);
|
||||
|
||||
// Now connect to the specific database
|
||||
$pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
|
||||
]);
|
||||
}
|
||||
return $pdo;
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, you'd log this error. For this demo, we'll just fail silently.
|
||||
// error_log('Database Connection Error: ' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
function pexels_key() {
|
||||
$k = getenv('PEXELS_KEY');
|
||||
return $k && strlen($k) > 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18';
|
||||
}
|
||||
function pexels_get($url) {
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ],
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
]);
|
||||
$resp = curl_exec($ch);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true);
|
||||
return null;
|
||||
}
|
||||
function download_to($srcUrl, $destPath) {
|
||||
$data = file_get_contents($srcUrl);
|
||||
if ($data === false) return false;
|
||||
if (!is_dir(dirname($destPath))) mkdir(dirname($destPath), 0775, true);
|
||||
return file_put_contents($destPath, $data) !== false;
|
||||
}
|
||||
?>
|
||||
200
index.php
200
index.php
@ -1,91 +1,131 @@
|
||||
<!DOCTYPE html>
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
@ini_set('display_errors', '1');
|
||||
@error_reporting(E_ALL);
|
||||
@date_default_timezone_set('UTC');
|
||||
|
||||
$phpVersion = PHP_VERSION;
|
||||
$now = date('Y-m-d H:i:s');
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Flatlogic LAMP Demo</title>
|
||||
<meta name="description" content="A playful demo site that shows what the new Flatlogic LAMP template can do.">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>New Style</title>
|
||||
<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=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
@keyframes bg-pan {
|
||||
0% { background-position: 0% 0%; }
|
||||
100% { background-position: 100% 100%; }
|
||||
}
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.loader {
|
||||
margin: 1.25rem auto 1.25rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.hint {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; border: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
code {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php include 'navbar.php'; ?>
|
||||
|
||||
<main>
|
||||
<section class="hero text-center">
|
||||
<div class="container">
|
||||
<h1 class="display-3 fw-bold">Generate a Website With a Vibe</h1>
|
||||
<p class="lead col-lg-8 mx-auto text-muted">Tell our AI your vibe, and we'll spin up a micro-site in seconds. From Synthwave to Brutalism, discover your digital aesthetic.</p>
|
||||
<a href="vibe.php" class="btn btn-primary btn-lg px-4">
|
||||
<i class="bi bi-stars"></i>
|
||||
Create a Vibe Site
|
||||
</a>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your website…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="py-5 bg-light">
|
||||
<div class="container">
|
||||
<div class="row text-center g-4">
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100 p-4">
|
||||
<img id="img-vibe" src="https://picsum.photos/seed/lamp-vibe/800/600" class="card-img-top rounded mb-3" alt="A colorful, abstract image representing different design vibes.">
|
||||
<div class="card-body">
|
||||
<h3 class="h4">Vibe Generator</h3>
|
||||
<p>Choose a vibe, give us a keyword, and watch the magic happen. Your own micro-site, generated by AI.</p>
|
||||
<p class="hint">Flatlogic AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100 p-4">
|
||||
<img id="img-code" src="https://picsum.photos/seed/lamp-code/800/600" class="card-img-top rounded mb-3" alt="A snippet of code on a dark background, representing the PHP sandbox.">
|
||||
<div class="card-body">
|
||||
<h3 class="h4">PHP Sandbox</h3>
|
||||
<p>Safely run PHP code snippets in an isolated environment. Perfect for testing and learning.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100 p-4">
|
||||
<img id="img-seo" src="https://picsum.photos/seed/lamp-seo/800/600" class="card-img-top rounded mb-3" alt="A magnifying glass over a web page, symbolizing SEO analysis.">
|
||||
<div class="card-body">
|
||||
<h3 class="h4">SEO Checker</h3>
|
||||
<p>Paste your HTML and get instant feedback on your on-page SEO, powered by AI analysis.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer class="py-5 bg-dark text-white">
|
||||
<div class="container text-center">
|
||||
<p class="mb-0">© <?php echo date("Y"); ?> Flatlogic. All rights reserved.</p>
|
||||
<p class="mb-0">
|
||||
<a href="contact.php" class="text-white">Contact</a> |
|
||||
<a href="#" class="text-white">Privacy Policy</a> |
|
||||
<a href="#" class="text-white">Terms of Service</a>
|
||||
</p>
|
||||
</div>
|
||||
<footer>
|
||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
fetch('api/pexels.php?queries=vibe,code,seo')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data && data.length === 3) {
|
||||
document.getElementById('img-vibe').src = data[0].src;
|
||||
document.getElementById('img-code').src = data[1].src;
|
||||
document.getElementById('img-seo').src = data[2].src;
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error fetching images:', error));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
31
navbar.php
31
navbar.php
@ -1,31 +0,0 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="index.php">Flatlogic</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="vibe.php">Vibe Generator</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="sandbox.php">PHP Sandbox</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="seo.php">SEO Checker</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contact.php">Contact</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="admin.php">Admin</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
55
sandbox.php
55
sandbox.php
@ -1,55 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PHP Sandbox</title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="assets/css/vibe.css">
|
||||
</head>
|
||||
<body>
|
||||
<?php include 'navbar.php'; ?>
|
||||
<div class="container mt-5">
|
||||
<h1>PHP Sandbox</h1>
|
||||
<p>Write and execute PHP code in a sandboxed environment.</p>
|
||||
<form method="post">
|
||||
<div class="form-group">
|
||||
<textarea name="code" class="form-control" rows="10" placeholder="Enter your PHP code here..."><?php echo isset($_POST['code']) ? htmlspecialchars($_POST['code']) : ''; ?></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Execute</button>
|
||||
</form>
|
||||
<hr>
|
||||
<?php
|
||||
function execute_php_code($code) {
|
||||
if (strpos(trim($code), '<?php') !== 0) {
|
||||
$code = '<?php ' . $code;
|
||||
}
|
||||
$descriptorspec = [
|
||||
0 => ["pipe", "r"],
|
||||
1 => ["pipe", "w"],
|
||||
2 => ["pipe", "w"]
|
||||
];
|
||||
$process = proc_open('php', $descriptorspec, $pipes);
|
||||
if (is_resource($process)) {
|
||||
fwrite($pipes[0], $code);
|
||||
fclose($pipes[0]);
|
||||
$output = stream_get_contents($pipes[1]);
|
||||
fclose($pipes[1]);
|
||||
$error = stream_get_contents($pipes[2]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
return $output ?: $error;
|
||||
}
|
||||
return 'Failed to create process.';
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['code'])) {
|
||||
$code = $_POST['code'];
|
||||
$output = execute_php_code($code);
|
||||
echo '<h3>Output:</h3>';
|
||||
echo '<pre>' . htmlspecialchars($output) . '</pre>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
168
seo.php
168
seo.php
@ -1,168 +0,0 @@
|
||||
<?php
|
||||
|
||||
function analyze_seo($html) {
|
||||
$results = [
|
||||
'title' => ['text' => '', 'length' => 0, 'status' => 'danger'],
|
||||
'description' => ['text' => '', 'length' => 0, 'status' => 'danger'],
|
||||
'h1_count' => ['count' => 0, 'status' => 'danger'],
|
||||
'alt_tags' => ['missing' => 0, 'total' => 0, 'status' => 'success'],
|
||||
'og_tags' => ['found' => 0, 'status' => 'warning'],
|
||||
];
|
||||
|
||||
if (empty($html)) return $results;
|
||||
|
||||
$doc = new DOMDocument();
|
||||
@$doc->loadHTML($html);
|
||||
|
||||
// Title
|
||||
$title_node = $doc->getElementsByTagName('title')->item(0);
|
||||
if ($title_node) {
|
||||
$results['title']['text'] = trim($title_node->nodeValue);
|
||||
$results['title']['length'] = strlen($results['title']['text']);
|
||||
if ($results['title']['length'] >= 10 && $results['title']['length'] <= 70) {
|
||||
$results['title']['status'] = 'success';
|
||||
}
|
||||
}
|
||||
|
||||
// Meta Description
|
||||
$metas = $doc->getElementsByTagName('meta');
|
||||
foreach ($metas as $meta) {
|
||||
$name = strtolower($meta->getAttribute('name'));
|
||||
$property = strtolower($meta->getAttribute('property'));
|
||||
if ($name == 'description') {
|
||||
$results['description']['text'] = trim($meta->getAttribute('content'));
|
||||
$results['description']['length'] = strlen($results['description']['text']);
|
||||
if ($results['description']['length'] >= 50 && $results['description']['length'] <= 160) {
|
||||
$results['description']['status'] = 'success';
|
||||
}
|
||||
}
|
||||
if (strpos($property, 'og:') === 0) {
|
||||
$results['og_tags']['found']++;
|
||||
}
|
||||
}
|
||||
if ($results['og_tags']['found'] >= 3) { // og:title, og:description, og:image
|
||||
$results['og_tags']['status'] = 'success';
|
||||
}
|
||||
|
||||
// H1 Count
|
||||
$h1s = $doc->getElementsByTagName('h1');
|
||||
$results['h1_count']['count'] = $h1s->length;
|
||||
if ($results['h1_count']['count'] === 1) {
|
||||
$results['h1_count']['status'] = 'success';
|
||||
}
|
||||
|
||||
// Alt Tags
|
||||
$images = $doc->getElementsByTagName('img');
|
||||
$results['alt_tags']['total'] = $images->length;
|
||||
foreach ($images as $img) {
|
||||
if (!$img->hasAttribute('alt') || trim($img->getAttribute('alt')) == '') {
|
||||
$results['alt_tags']['missing']++;
|
||||
}
|
||||
}
|
||||
if ($results['alt_tags']['total'] > 0 && $results['alt_tags']['missing'] > 0) {
|
||||
$results['alt_tags']['status'] = 'warning';
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
$url_input = '';
|
||||
$seo_results = null;
|
||||
$error_message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['url'])) {
|
||||
$url_input = trim($_POST['url']);
|
||||
if (filter_var($url_input, FILTER_VALIDATE_URL)) {
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'timeout' => 10, // 10 seconds
|
||||
'user_agent' => 'FlatlogicSEOChecker/1.0',
|
||||
]
|
||||
]);
|
||||
$html = @file_get_contents($url_input, false, $context);
|
||||
if ($html) {
|
||||
$seo_results = analyze_seo($html);
|
||||
} else {
|
||||
$error_message = "Could not retrieve content from the URL. Please check if the URL is correct and publicly accessible.";
|
||||
}
|
||||
} else {
|
||||
$error_message = "Invalid URL provided. Please enter a valid URL (e.g., http://example.com).";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SEO Checker - LAMP Demo</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<?php include 'navbar.php'; ?>
|
||||
|
||||
<main class="container my-5">
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="display-5">Live SEO Checker</h1>
|
||||
<p class="lead">Enter a URL to get an on-page SEO analysis.</p>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-4">
|
||||
<form action="seo.php" method="POST">
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text"><i class="bi bi-link-45deg"></i></span>
|
||||
<input type="url" class="form-control form-control-lg" id="url" name="url" placeholder="https://example.com" value="<?php echo htmlspecialchars($url_input); ?>" required>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-search"></i> Analyze</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger mt-3"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($seo_results): ?>
|
||||
<div class="card shadow-sm mt-5">
|
||||
<div class="card-header">
|
||||
<h2 class="h4 mb-0">Analysis Results for <span class="text-primary"><?php echo htmlspecialchars($url_input); ?></span></h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div><strong>Title Tag</strong> <span class="badge bg-<?php echo $seo_results['title']['status']; ?>"><?php echo $seo_results['title']['length'] > 0 ? 'OK' : 'Missing'; ?></span><br><small class="text-muted"><?php echo htmlspecialchars($seo_results['title']['text']); ?> (<?php echo $seo_results['title']['length']; ?> chars)</small></div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div><strong>Meta Description</strong> <span class="badge bg-<?php echo $seo_results['description']['status']; ?>"><?php echo $seo_results['description']['length'] > 0 ? 'OK' : 'Missing'; ?></span><br><small class="text-muted"><?php echo htmlspecialchars(substr($seo_results['description']['text'], 0, 150)); ?>... (<?php echo $seo_results['description']['length']; ?> chars)</small></div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div><strong>H1 Tags</strong> <small class="text-muted">Should be exactly one.</small></div>
|
||||
<span class="badge bg-<?php echo $seo_results['h1_count']['status']; ?>"><?php echo $seo_results['h1_count']['count']; ?> found</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div><strong>Image Alt Tags</strong> <small class="text-muted">All images should have descriptive alt text.</small></div>
|
||||
<span class="badge bg-<?php echo $seo_results['alt_tags']['status']; ?>"><?php echo $seo_results['alt_tags']['missing']; ?> missing / <?php echo $seo_results['alt_tags']['total']; ?> total</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div><strong>Open Graph Tags</strong> <small class="text-muted">For social media sharing.</small></div>
|
||||
<span class="badge bg-<?php echo $seo_results['og_tags']['status']; ?>"><?php echo $seo_results['og_tags']['found']; ?> found</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
|
||||
<footer class="bg-white text-center text-muted py-4 mt-5 border-top">
|
||||
<div class="container">
|
||||
<p class="mb-0">© <?php echo date("Y"); ?> LAMP Demo. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
106
vibe-share.php
106
vibe-share.php
@ -1,106 +0,0 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
function get_vibe_css($vibe) {
|
||||
$css = '';
|
||||
switch ($vibe) {
|
||||
case 'Tech-retro':
|
||||
$css = 'body { font-family: "Courier New", monospace; background-color: #000; color: #0FF; } .navbar, .card, footer { background-color: #002B36 !important; border: 1px solid #0FF; } .navbar-brand, .nav-link, h1, h2, h5, p { color: #0FF !important; } .btn-primary { background-color: #0FF; color: #000; border: none; } .vibe-preview { padding: 2rem; border: 1px dashed #0FF; margin-top: 2rem; }';
|
||||
break;
|
||||
case 'Synthwave':
|
||||
$css = '@import url("https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap"); body { font-family: "Orbitron", sans-serif; background: linear-gradient(to bottom, #2c003e, #ff00c1); color: #fff; } .navbar, .card, footer { background-color: rgba(0,0,0,0.5) !important; backdrop-filter: blur(10px); border: 1px solid #ff00c1; } .navbar-brand, .nav-link, h1, h2, h5, p { color: #fff !important; text-shadow: 0 0 10px #ff00c1; } .btn-primary { background: #ff00c1; border: none; box-shadow: 0 0 15px #ff00c1; } .vibe-preview { padding: 2rem; border: 1px solid #ff00c1; margin-top: 2rem; }';
|
||||
break;
|
||||
case 'Brutalism':
|
||||
$css = 'body { font-family: "Arial", sans-serif; background-color: #f0f0f0; color: #000; } .navbar, .card, footer { background-color: #f0f0f0 !important; border: 2px solid #000; box-shadow: none !important; border-radius: 0; } .navbar-brand, .nav-link, h1, h2, h5, p { color: #000 !important; } .btn-primary { background-color: #FFFF00; color: #000; border: 2px solid #000; border-radius: 0; } .vibe-preview { padding: 2rem; border: 2px solid #000; margin-top: 2rem; }';
|
||||
break;
|
||||
case 'Dad-garage':
|
||||
$css = '@import url("https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;700&display=swap"); body { font-family: "Roboto Slab", serif; background-color: #D2B48C; color: #333; } .navbar, .card, footer { background-color: #8B4513 !important; color: white; border: 3px solid #654321; } .navbar-brand, .nav-link, h1, h2, h5, p, .card-body { color: #fff !important; } .btn-primary { background-color: #008000; color: #fff; border: 2px solid #006400; } .vibe-preview { padding: 2rem; border: 2px solid #654321; margin-top: 2rem; background-color: #F5DEB3; } .vibe-preview h2, .vibe-preview p { color: #333 !important; }';
|
||||
break;
|
||||
case 'Zen-mono':
|
||||
$css = 'body { font-family: "Helvetica Neue", sans-serif; background-color: #fff; color: #333; } .navbar, .card, footer { background-color: #fff !important; border: 1px solid #ddd; box-shadow: none !important; } .navbar-brand, .nav-link, h1, h2, h5, p { color: #333 !important; } .btn-primary { background-color: #333; color: #fff; border: none; border-radius: 50px; } .vibe-preview { padding: 2rem; border: 1px solid #eee; margin-top: 2rem; }';
|
||||
break;
|
||||
}
|
||||
return $css;
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
$saved_vibe = null;
|
||||
|
||||
if (isset($_GET['id']) && $pdo) {
|
||||
$stmt = $pdo->prepare('SELECT id, vibe, keywords, created_at FROM saved_vibes WHERE id = ?');
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$saved_vibe = $stmt->fetch();
|
||||
}
|
||||
|
||||
$vibe_css = '';
|
||||
if ($saved_vibe) {
|
||||
$vibe_css = get_vibe_css($saved_vibe['vibe']);
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Shared Vibe - <?php echo htmlspecialchars($saved_vibe['keywords'] ?? 'Not Found'); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
<?php if ($vibe_css): ?>
|
||||
<style><?php echo $vibe_css; ?></style>
|
||||
<?php endif; ?>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php"><i class="bi bi-lightbulb-fill text-primary"></i> LAMP Demo</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"><span class="navbar-toggler-icon"></span></button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item"><a class="nav-link" href="index.php">Home</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="vibe.php">Vibe</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="sandbox.php">Sandbox</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="seo.php">SEO</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="admin.php">Admin</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="contact.php">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="py-5">
|
||||
<div class="container">
|
||||
<?php if ($saved_vibe): ?>
|
||||
<div class="vibe-preview">
|
||||
<div class="text-center">
|
||||
<h1><?php echo htmlspecialchars($saved_vibe['keywords']); ?></h1>
|
||||
<p>A micro-site generated with the <span class="badge bg-secondary"><?php echo htmlspecialchars($saved_vibe['vibe']); ?></span> vibe.</p>
|
||||
</div>
|
||||
<div class="row mt-5">
|
||||
<div class="col-md-4"><div class="card"><div class="card-body"><h5 class="card-title">Feature One</h5><p class="card-text">This is a sample card.</p></div></div></div>
|
||||
<div class="col-md-4"><div class="card"><div class="card-body"><h5 class="card-title">Feature Two</h5><p class="card-text">Styles are from the vibe.</p></div></div></div>
|
||||
<div class="col-md-4"><div class="card"><div class="card-body"><h5 class="card-title">Feature Three</h5><p class="card-text">Create your own vibe!</p></div></div></div>
|
||||
</div>
|
||||
<div class="text-center mt-5">
|
||||
<a href="vibe.php" class="btn btn-primary">Create Your Own Vibe</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="text-center">
|
||||
<h1 class="display-5">Vibe Not Found</h1>
|
||||
<p class="lead">Sorry, we couldn't find the vibe you were looking for.</p>
|
||||
<a href="vibe.php" class="btn btn-primary">Explore Other Vibes</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="py-4 mt-auto bg-light">
|
||||
<div class="container text-center"><p class="mb-0 text-muted">© <?php echo date("Y"); ?> Flatlogic. All rights reserved.</p></div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
180
vibe.php
180
vibe.php
@ -1,180 +0,0 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
function get_vibe_css($vibe) {
|
||||
$css = '';
|
||||
switch ($vibe) {
|
||||
case 'Tech-retro':
|
||||
$css = 'body { font-family: "Courier New", monospace; background-color: #000; color: #0FF; } .navbar, .card, footer { background-color: #002B36 !important; border: 1px solid #0FF; } .navbar-brand, .nav-link, h1, h2, h5, p { color: #0FF !important; } .btn-primary { background-color: #0FF; color: #000; border: none; } .vibe-preview { padding: 2rem; border: 1px dashed #0FF; margin-top: 2rem; }';
|
||||
break;
|
||||
case 'Synthwave':
|
||||
$css = '@import url("https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap"); body { font-family: "Orbitron", sans-serif; background: linear-gradient(to bottom, #2c003e, #ff00c1); color: #fff; } .navbar, .card, footer { background-color: rgba(0,0,0,0.5) !important; backdrop-filter: blur(10px); border: 1px solid #ff00c1; } .navbar-brand, .nav-link, h1, h2, h5, p { color: #fff !important; text-shadow: 0 0 10px #ff00c1; } .btn-primary { background: #ff00c1; border: none; box-shadow: 0 0 15px #ff00c1; } .vibe-preview { padding: 2rem; border: 1px solid #ff00c1; margin-top: 2rem; }';
|
||||
break;
|
||||
case 'Brutalism':
|
||||
$css = 'body { font-family: "Arial", sans-serif; background-color: #f0f0f0; color: #000; } .navbar, .card, footer { background-color: #f0f0f0 !important; border: 2px solid #000; box-shadow: none !important; border-radius: 0; } .navbar-brand, .nav-link, h1, h2, h5, p { color: #000 !important; } .btn-primary { background-color: #FFFF00; color: #000; border: 2px solid #000; border-radius: 0; } .vibe-preview { padding: 2rem; border: 2px solid #000; margin-top: 2rem; }';
|
||||
break;
|
||||
case 'Dad-garage':
|
||||
$css = '@import url("https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;700&display=swap"); body { font-family: "Roboto Slab", serif; background-color: #D2B48C; color: #333; } .navbar, .card, footer { background-color: #8B4513 !important; color: white; border: 3px solid #654321; } .navbar-brand, .nav-link, h1, h2, h5, p, .card-body { color: #fff !important; } .btn-primary { background-color: #008000; color: #fff; border: 2px solid #006400; } .vibe-preview { padding: 2rem; border: 2px solid #654321; margin-top: 2rem; background-color: #F5DEB3; } .vibe-preview h2, .vibe-preview p { color: #333 !important; }';
|
||||
break;
|
||||
case 'Zen-mono':
|
||||
$css = 'body { font-family: "Helvetica Neue", sans-serif; background-color: #fff; color: #333; } .navbar, .card, footer { background-color: #fff !important; border: 1px solid #ddd; box-shadow: none !important; } .navbar-brand, .nav-link, h1, h2, h5, p { color: #333 !important; } .btn-primary { background-color: #333; color: #fff; border: none; border-radius: 50px; } .vibe-preview { padding: 2rem; border: 1px solid #eee; margin-top: 2rem; }';
|
||||
break;
|
||||
}
|
||||
return $css;
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
$vibe_css_path = 'assets/css/vibe.css';
|
||||
$vibe_generated = false;
|
||||
$saved_vibe_id = null;
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$vibe = $_POST['vibe'] ?? '';
|
||||
$keywords = $_POST['keywords'] ?? '';
|
||||
$action = $_POST['action'] ?? 'generate';
|
||||
|
||||
if ($action === 'save' && $pdo) {
|
||||
$stmt = $pdo->prepare('INSERT INTO saved_vibes (vibe, keywords) VALUES (?, ?)');
|
||||
$stmt->execute([$vibe, $keywords]);
|
||||
$saved_vibe_id = $pdo->lastInsertId();
|
||||
header("Location: vibe.php?saved_id=" . $saved_vibe_id);
|
||||
exit;
|
||||
} elseif ($action === 'generate' && $vibe) {
|
||||
$css_content = get_vibe_css($vibe);
|
||||
file_put_contents($vibe_css_path, $css_content);
|
||||
$vibe_generated = true;
|
||||
}
|
||||
}
|
||||
|
||||
$saved_vibes = [];
|
||||
if ($pdo) {
|
||||
$stmt = $pdo->query('SELECT id, vibe, keywords, created_at FROM saved_vibes ORDER BY created_at DESC');
|
||||
$saved_vibes = $stmt->fetchAll();
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vibe Generator - LAMP Demo</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
<?php if ($vibe_generated && file_exists($vibe_css_path)): ?>
|
||||
<link rel="stylesheet" href="<?php echo $vibe_css_path; ?>?v=<?php echo time(); ?>">
|
||||
<?php endif; ?>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<?php include 'navbar.php'; ?>
|
||||
|
||||
<main class="py-5">
|
||||
<div class="container">
|
||||
<?php if (isset($_GET['saved_id'])): ?>
|
||||
<div class="alert alert-success text-center">
|
||||
<h4>Vibe Saved!</h4>
|
||||
<p>Your vibe has been saved. You can share it with this link:</p>
|
||||
<input type="text" class="form-control text-center" value="<?php echo htmlspecialchars("http://{$_SERVER['HTTP_HOST']}/vibe-share.php?id={$_GET['saved_id']}"); ?>" readonly>
|
||||
<div class="mt-3">
|
||||
<a href="vibe-share.php?id=<?php echo htmlspecialchars($_GET['saved_id']); ?>" class="btn btn-primary">View Saved Vibe</a>
|
||||
<a href="vibe.php" class="btn btn-secondary">Create Another</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!$vibe_generated): ?>
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="display-5">Create a Vibe Site</h1>
|
||||
<p class="lead">Choose an aesthetic, provide keywords, and generate a themed micro-site.</p>
|
||||
</div>
|
||||
|
||||
<form action="vibe.php" method="POST">
|
||||
<input type="hidden" name="action" value="generate">
|
||||
<div class="row g-4 justify-content-center text-center">
|
||||
<h2 class="h4">1. Choose a Vibe</h2>
|
||||
<?php
|
||||
$vibes = [
|
||||
'Tech-retro' => ['icon' => 'bi-pc-display-horizontal', 'desc' => '90s nostalgia, pixelated and chunky.'],
|
||||
'Synthwave' => ['icon' => 'bi-sunset', 'desc' => 'Neon grids, chrome, and 80s futurism.'],
|
||||
'Brutalism' => ['icon' => 'bi-building', 'desc' => 'Raw, blocky, and unapologetically functional.'],
|
||||
'Dad-garage' => ['icon' => 'bi-tools', 'desc' => 'Rugged, practical, and built to last.'],
|
||||
'Zen-mono' => ['icon' => 'bi-yin-yang', 'desc' => 'Minimalist, monochrome, and serene.']
|
||||
];
|
||||
foreach ($vibes as $name => $details):
|
||||
?>
|
||||
<div class="col-md-4 col-lg-2">
|
||||
<label class="card h-100 vibe-option p-3">
|
||||
<input type="radio" name="vibe" value="<?php echo htmlspecialchars($name); ?>" required>
|
||||
<div class="vibe-icon"><i class="bi <?php echo $details['icon']; ?>"></i></div>
|
||||
<h5 class="h6"><?php echo htmlspecialchars($name); ?></h5>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($details['desc']); ?></small>
|
||||
</label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center mt-5">
|
||||
<div class="col-lg-6">
|
||||
<h2 class="h4 text-center">2. Enter Keywords</h2>
|
||||
<input type="text" class="form-control form-control-lg" name="keywords" placeholder="e.g., My personal blog, AI experiments" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-4"><button type="submit" class="btn btn-primary btn-lg"><i class="bi bi-stars"></i> Generate</button></div>
|
||||
</form>
|
||||
|
||||
<?php if (!empty($saved_vibes)): ?>
|
||||
<div class="mt-5 pt-5 border-top">
|
||||
<h2 class="text-center mb-4">Previously Saved Vibes</h2>
|
||||
<div class="row g-4">
|
||||
<?php foreach ($saved_vibes as $item): ?>
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title"><?php echo htmlspecialchars($item['keywords']); ?></h5>
|
||||
<p class="card-text"><span class="badge bg-secondary"><?php echo htmlspecialchars($item['vibe']); ?></span></p>
|
||||
<a href="vibe-share.php?id=<?php echo $item['id']; ?>" class="btn btn-sm btn-outline-primary">View Vibe</a>
|
||||
</div>
|
||||
<div class="card-footer text-muted text-center"><small>Created: <?php echo date("M j, Y", strtotime($item['created_at'])); ?></small></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php else: ?>
|
||||
<div class="vibe-preview">
|
||||
<div class="text-center">
|
||||
<h1><?php echo htmlspecialchars($keywords); ?></h1>
|
||||
<p>A micro-site generated with the <span class="badge bg-secondary"><?php echo htmlspecialchars($vibe); ?></span> vibe.</p>
|
||||
</div>
|
||||
<div class="row mt-5">
|
||||
<div class="col-md-4"><div class="card"><div class="card-body"><h5 class="card-title">Feature One</h5><p class="card-text">This is a sample card.</p></div></div></div>
|
||||
<div class="col-md-4"><div class="card"><div class="card-body"><h5 class="card-title">Feature Two</h5><p class="card-text">Styles are from the vibe.</p></div></div></div>
|
||||
<div class="col-md-4"><div class="card"><div class="card-body"><h5 class="card-title">Feature Three</h5><p class="card-text">Save or start over.</p></div></div></div>
|
||||
</div>
|
||||
<div class="text-center mt-5">
|
||||
<form action="vibe.php" method="POST" class="d-inline">
|
||||
<input type="hidden" name="action" value="save">
|
||||
<input type="hidden" name="vibe" value="<?php echo htmlspecialchars($vibe); ?>">
|
||||
<input type="hidden" name="keywords" value="<?php echo htmlspecialchars($keywords); ?>">
|
||||
<button type="submit" class="btn btn-success btn-lg"><i class="bi bi-save"></i> Save Vibe</button>
|
||||
</form>
|
||||
<a href="vibe.php" class="btn btn-secondary btn-lg">Start Over</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="py-4 mt-auto bg-light">
|
||||
<div class="container text-center"><p class="mb-0 text-muted">© <?php echo date("Y"); ?> Flatlogic. All rights reserved.</p></div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user